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. 12
      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. 65
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ImplementAbstractMembersAction.cs
  19. 246
      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. 41
      ICSharpCode.NRefactory.CSharp/Resolver/DynamicInvocationResolveResult.cs
  25. 45
      ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs
  26. 134
      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. 6
      ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/EventDeclarationTests.cs
  43. 49
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs
  44. 612
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/DynamicTests.cs
  45. 117
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/ExtensionMethodTests.cs
  46. 41
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/ObjectCreationTests.cs
  47. 24
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/TypeInferenceTests.cs
  48. 21
      ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefLookupTests.cs
  49. 20
      ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefParserTests.cs
  50. 71
      ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs
  51. 17
      ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs
  52. 38
      ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs
  53. 2
      ICSharpCode.NRefactory/Properties/GlobalAssemblyInfo.cs
  54. 16
      ICSharpCode.NRefactory/Semantics/Conversion.cs
  55. 2
      ICSharpCode.NRefactory/Semantics/MemberResolveResult.cs
  56. 95
      ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs
  57. 6
      ICSharpCode.NRefactory/TypeSystem/IAssembly.cs
  58. 5
      ICSharpCode.NRefactory/TypeSystem/INamespace.cs
  59. 5
      ICSharpCode.NRefactory/TypeSystem/IProjectContent.cs
  60. 2
      ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs
  61. 25
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedMethod.cs
  62. 15
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs
  63. 5
      ICSharpCode.NRefactory/TypeSystem/Implementation/MergedNamespace.cs
  64. 3
      ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs
  65. 4
      Packages/ICSharpCode.NRefactory.nuspec

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

@ -721,7 +721,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis @@ -721,7 +721,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
}
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));
}
}

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

@ -62,12 +62,29 @@ namespace ICSharpCode.NRefactory.CSharp @@ -62,12 +62,29 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildrenByRole(MemberRole); }
}
IList<string> conditionalSymbols = null;
List<Error> errors = new List<Error> ();
public List<Error> 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>
/// 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.

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -3472,6 +3472,73 @@ namespace ICSharpCode.NRefactory.CSharp @@ -3472,6 +3472,73 @@ namespace ICSharpCode.NRefactory.CSharp
return result;
}
#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 ()
@ -3672,7 +3739,9 @@ namespace ICSharpCode.NRefactory.CSharp @@ -3672,7 +3739,9 @@ namespace ICSharpCode.NRefactory.CSharp
if (top.LastYYValue is Mono.CSharp.Expression) {
conversionVisitor.Unit.TopExpression = ((Mono.CSharp.Expression)top.LastYYValue).Accept(conversionVisitor) as AstNode;
}
conversionVisitor.Unit.FileName = fileName;
conversionVisitor.Unit.ConditionalSymbols = top.Conditionals.ToArray ();
return conversionVisitor.Unit;
}
@ -3717,7 +3786,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -3717,7 +3786,8 @@ namespace ICSharpCode.NRefactory.CSharp
var top = new CompilerCompilationUnit () {
ModuleCompiled = module,
LocationsBag = parser.LocationsBag,
SpecialsBag = parser.Lexer.sbag
SpecialsBag = parser.Lexer.sbag,
Conditionals = parser.Lexer.SourceFile.Conditionals
};
var unit = Parse (top, fileName, lineModifier);
unit.Errors.AddRange (errorReportPrinter.Errors);
@ -3733,8 +3803,13 @@ namespace ICSharpCode.NRefactory.CSharp @@ -3733,8 +3803,13 @@ namespace ICSharpCode.NRefactory.CSharp
if (cu == null)
return Enumerable.Empty<EntityDeclaration> ();
var td = cu.Children.FirstOrDefault () as TypeDeclaration;
if (td != null)
return td.Members;
if (td != null) {
var members = td.Members.ToArray();
// detach members from parent
foreach (var m in members)
m.Remove();
return members;
}
return Enumerable.Empty<EntityDeclaration> ();
}
@ -3743,8 +3818,13 @@ namespace ICSharpCode.NRefactory.CSharp @@ -3743,8 +3818,13 @@ namespace ICSharpCode.NRefactory.CSharp
string code = "void M() { " + Environment.NewLine + reader.ReadToEnd () + "}";
var members = ParseTypeMembers (new StringReader (code), lineModifier - 1);
var method = members.FirstOrDefault () as MethodDeclaration;
if (method != null && method.Body != null)
return method.Body.Statements;
if (method != null && method.Body != null) {
var statements = method.Body.Statements.ToArray();
// detach statements from parent
foreach (var st in statements)
st.Remove();
return statements;
}
return Enumerable.Empty<Statement> ();
}
@ -3753,8 +3833,11 @@ namespace ICSharpCode.NRefactory.CSharp @@ -3753,8 +3833,11 @@ namespace ICSharpCode.NRefactory.CSharp
string code = reader.ReadToEnd () + " a;";
var members = ParseTypeMembers (new StringReader (code));
var field = members.FirstOrDefault () as FieldDeclaration;
if (field != null)
return field.ReturnType;
if (field != null) {
AstType type = field.ReturnType;
type.Remove();
return type;
}
return AstType.Null;
}
@ -3763,8 +3846,11 @@ namespace ICSharpCode.NRefactory.CSharp @@ -3763,8 +3846,11 @@ namespace ICSharpCode.NRefactory.CSharp
var es = ParseStatements (new StringReader ("tmp = " + Environment.NewLine + reader.ReadToEnd () + ";"), -1).FirstOrDefault () as ExpressionStatement;
if (es != null) {
AssignmentExpression ae = es.Expression as AssignmentExpression;
if (ae != null)
return ae.Right;
if (ae != null) {
Expression expr = ae.Right;
expr.Remove();
return expr;
}
}
return Expression.Null;
}
@ -3780,12 +3866,39 @@ namespace ICSharpCode.NRefactory.CSharp @@ -3780,12 +3866,39 @@ namespace ICSharpCode.NRefactory.CSharp
public DocumentationReference ParseDocumentationReference (string cref)
{
// see Mono.CSharp.DocumentationBuilder.HandleXrefCommon
if (cref == null)
throw new ArgumentNullException ("cref");
// Additional symbols for < and > are allowed for easier XML typing
cref = cref.Replace ('{', '<').Replace ('}', '>');
// TODO: add support for parsing cref attributes
// (documentation_parsing production, see DocumentationBuilder.HandleXrefCommon)
throw new NotImplementedException ();
lock (parseLock) {
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 @@ -174,6 +174,13 @@ namespace Mono.CSharp
readonly SeekableStreamReader reader;
readonly CompilationSourceFile source_file;
public CompilationSourceFile SourceFile {
get {
return source_file;
}
}
readonly CompilerContext context;
SourceFile current_source;

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

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

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

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

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

@ -591,6 +591,14 @@ namespace Mono.CSharp { @@ -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 {
get {
return file.Name;

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

@ -80,11 +80,18 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod @@ -80,11 +80,18 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod
if (!StaticVisitor.UsesNotStaticMember(context, expression))
method.Modifiers |= Modifiers.Static;
var task = script.InsertWithCursor(context.TranslateString("Extract method"), Script.InsertPosition.Before, method);
task.ContinueWith (delegate {
Action<Task> replaceStatements = delegate {
var target = new IdentifierExpression(methodName);
script.Replace(expression, new InvocationExpression(target));
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 @@ -113,84 +120,87 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod
var usedVariables = VariableLookupVisitor.Analyze(context, statements);
var extractedCodeAnalysis = new DefiniteAssignmentAnalysis(
(Statement)statements [0].Parent,
context.Resolver,
context.CancellationToken);
var inExtractedRegion = new VariableUsageAnalyzation (context, usedVariables);
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>();
while (stmt.GetParent<BlockStatement> () != null) {
stmt = stmt.GetParent<BlockStatement>();
}
var wholeCodeAnalysis = new DefiniteAssignmentAnalysis(stmt, context.Resolver, context.CancellationToken);
var statusBeforeMethod = new Dictionary<IVariable, DefiniteAssignmentStatus>();
foreach (var variable in usedVariables) {
wholeCodeAnalysis.Analyze(variable.Name, DefiniteAssignmentStatus.PotentiallyAssigned, context.CancellationToken);
statusBeforeMethod [variable] = extractedCodeAnalysis.GetStatusBefore(statements [0]);
}
inExtractedRegion.SetAnalyzedRange(statements [0], lastStatement);
stmt.AcceptVisitor (inExtractedRegion);
var beforeExtractedRegion = new VariableUsageAnalyzation (context, usedVariables);
beforeExtractedRegion.SetAnalyzedRange(statements [0].Parent, statements [0], true, false);
stmt.AcceptVisitor (beforeExtractedRegion);
var afterCodeAnalysis = new DefiniteAssignmentAnalysis(stmt, context.Resolver, context.CancellationToken);
var statusAtEnd = new Dictionary<IVariable, DefiniteAssignmentStatus>();
afterCodeAnalysis.SetAnalyzedRange(lastStatement, stmt.Statements.Last(), false, true);
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) {
afterCodeAnalysis.Analyze(variable.Name, DefiniteAssignmentStatus.PotentiallyAssigned, context.CancellationToken);
statusBeforeMethod [variable] = extractedCodeAnalysis.GetStatusBefore(statements [0]);
if ((variable is IParameter) || beforeExtractedRegion.Has (variable) || !afterExtractedRegion.Has (variable))
continue;
generatedReturnVariable = variable;
method.ReturnType = context.CreateShortType (variable.Type);
method.Body.Add (new ReturnStatement (new IdentifierExpression (variable.Name)));
break;
}
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))
foreach (var variable in usedVariables) {
if (!(variable is IParameter) && !beforeExtractedRegion.Has (variable) && !afterExtractedRegion.Has (variable))
continue;
if (variable == generatedReturnVariable)
continue;
Expression argumentExpression = new IdentifierExpression(status.Item1.Name);
Expression argumentExpression = new IdentifierExpression(variable.Name);
ParameterModifier mod;
switch (status.Item2) {
case DefiniteAssignmentStatus.AssignedAfterTrueExpression:
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;
ParameterModifier mod = ParameterModifier.None;
if (inExtractedRegion.GetStatus (variable) == VariableState.Changed) {
if (beforeExtractedRegion.GetStatus (variable) == VariableState.None) {
mod = ParameterModifier.Out;
argumentExpression = new DirectionExpression(FieldDirection.Out, argumentExpression);
break;
// case DefiniteAssignmentStatus.Unassigned:
default:
mod = ParameterModifier.None;
break;
} else {
mod = ParameterModifier.Ref;
argumentExpression = new DirectionExpression(FieldDirection.Ref, argumentExpression);
}
}
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);
}
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)) {
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);
}, 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 @@ -39,12 +39,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod
TextLocation startLocation = TextLocation.Empty;
TextLocation endLocation = TextLocation.Empty;
public VariableLookupVisitor (RefactoringContext 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)
{
if (start == null)
@ -60,8 +64,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod @@ -60,8 +64,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod
if (startLocation.IsEmpty || startLocation <= identifierExpression.StartLocation && identifierExpression.EndLocation <= endLocation) {
var result = context.Resolve(identifierExpression);
var local = result as LocalResolveResult;
if (local != null && !UsedVariables.Contains(local.Variable))
if (local != null && !UsedVariables.Contains(local.Variable)) {
UsedVariables.Add(local.Variable);
}
}
}

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

@ -0,0 +1,146 @@ @@ -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);
}
}
}

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

@ -31,7 +31,7 @@ using System.Linq; @@ -31,7 +31,7 @@ using System.Linq;
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 IEnumerable<CodeAction> GetActions(RefactoringContext context)
@ -47,15 +47,70 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -47,15 +47,70 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
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 return new CodeAction(context.TranslateString("Implement abstract members"), script => {
script.InsertWithCursor(
context.TranslateString("Implement abstract members"),
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;
}
}
}

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

@ -23,7 +23,6 @@ @@ -23,7 +23,6 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.TypeSystem;
using System.Threading;
@ -32,7 +31,7 @@ using System.Linq; @@ -32,7 +31,7 @@ using System.Linq;
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 IEnumerable<CodeAction> GetActions(RefactoringContext context)
@ -48,19 +47,21 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -48,19 +47,21 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var resolveResult = context.Resolve(type);
if (resolveResult.Type.Kind != TypeKind.Interface)
yield break;
var toImplement = CollectMembersToImplement(state.CurrentTypeDefinition, resolveResult.Type, false);
if (toImplement.Count == 0)
yield break;
yield return new CodeAction(context.TranslateString("Implement interface"), script => {
script.InsertWithCursor(
context.TranslateString ("Implement Interface"),
context.TranslateString("Implement Interface"),
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>>();
@ -71,9 +72,15 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -71,9 +72,15 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
}
foreach (var kv in nodes) {
yield return new PreProcessorDirective(
PreProcessorDirectiveType.Region,
string.Format("{0} implementation", kv.Key.Name));
if (kv.Key.Kind == TypeKind.Interface) {
yield return new PreProcessorDirective(
PreProcessorDirectiveType.Region,
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)
yield return member;
yield return new PreProcessorDirective(
@ -86,11 +93,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -86,11 +93,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
switch (member.Item1.EntityType) {
case EntityType.Property:
return null;
return GenerateProperty(context, (IProperty)member.Item1, member.Item2);
case EntityType.Indexer:
return null;
return GenerateIndexer(context, (IProperty)member.Item1, member.Item2);
case EntityType.Event:
return null;
return GenerateEvent(context, (IEvent)member.Item1, member.Item2);
case EntityType.Method:
return GenerateMethod(context, (IMethod)member.Item1, member.Item2);
default:
@ -98,6 +105,114 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -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)
{
var result = new MethodDeclaration() {
@ -116,6 +231,29 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -116,6 +231,29 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
foreach (var typeParam in method.TypeParameters) {
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) {
@ -135,67 +273,73 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -135,67 +273,73 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return result;
}
public static List<Tuple<IMember, bool>> CollectMembersToImplement(ITypeDefinition implementingType, IType interfaceType, bool explicitly)
{
var def = interfaceType.GetDefinition();
List<Tuple<IMember, bool>> toImplement = new List<Tuple<IMember, bool>>();
bool alreadyImplemented;
// Stub out non-implemented events defined by @iface
foreach (var ev in interfaceType.GetEvents (e => !e.IsSynthetic && e.DeclaringTypeDefinition.ReflectionName == def.ReflectionName)) {
bool needsExplicitly = explicitly;
alreadyImplemented = implementingType.GetAllBaseTypeDefinitions().Any(
x => x.Kind != TypeKind.Interface && x.Events.Any (y => y.Name == ev.Name)
);
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;
alreadyImplemented = implementingType.GetAllBaseTypeDefinitions().Any(
x => x.Kind != TypeKind.Interface && x.Events.Any(y => y.Name == ev.Name)
);
if (!alreadyImplemented)
toImplement.Add(new Tuple<IMember, bool>(ev, needsExplicitly));
}
if (!alreadyImplemented)
toImplement.Add(new Tuple<IMember, bool>(ev, needsExplicitly));
}
// Stub out non-implemented methods defined by @iface
foreach (var method in interfaceType.GetMethods (d => !d.IsSynthetic && d.DeclaringTypeDefinition.ReflectionName == def.ReflectionName)) {
bool needsExplicitly = explicitly;
alreadyImplemented = false;
foreach (var cmet in implementingType.GetMethods ()) {
if (CompareMethods(method, cmet)) {
if (!needsExplicitly && !cmet.ReturnType.Equals(method.ReturnType))
needsExplicitly = true;
else
alreadyImplemented |= !needsExplicitly /*|| cmet.InterfaceImplementations.Any (impl => impl.InterfaceType.Equals (interfaceType))*/;
foreach (var methodGroup in interfaceType.GetMethods (d => !d.IsSynthetic).GroupBy (m => m.DeclaringType).Reverse ())
foreach (var method in methodGroup) {
bool needsExplicitly = explicitly;
alreadyImplemented = false;
foreach (var cmet in implementingType.GetMethods ()) {
if (CompareMethods(method, cmet)) {
if (!needsExplicitly && !cmet.ReturnType.Equals(method.ReturnType))
needsExplicitly = true;
else
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)
toImplement.Add(new Tuple<IMember, bool>(method, needsExplicitly));
}
if (!alreadyImplemented)
toImplement.Add(new Tuple<IMember, bool>(method, needsExplicitly));
}
// Stub out non-implemented properties defined by @iface
foreach (var prop in interfaceType.GetProperties (p => !p.IsSynthetic && p.DeclaringTypeDefinition.ReflectionName == def.ReflectionName)) {
bool needsExplicitly = explicitly;
alreadyImplemented = false;
foreach (var t in implementingType.GetAllBaseTypeDefinitions ()) {
if (t.Kind == TypeKind.Interface)
continue;
foreach (IProperty cprop in t.Properties) {
if (cprop.Name == prop.Name) {
if (!needsExplicitly && !cprop.ReturnType.Equals(prop.ReturnType))
needsExplicitly = true;
else
alreadyImplemented |= !needsExplicitly/* || cprop.InterfaceImplementations.Any (impl => impl.InterfaceType.Resolve (ctx).Equals (interfaceType))*/;
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;
alreadyImplemented = false;
foreach (var t in implementingType.GetAllBaseTypeDefinitions ()) {
if (t.Kind == TypeKind.Interface)
continue;
foreach (IProperty cprop in t.Properties) {
if (cprop.Name == prop.Name) {
if (!needsExplicitly && !cprop.ReturnType.Equals(prop.ReturnType))
needsExplicitly = true;
else
alreadyImplemented |= !needsExplicitly/* || cprop.InterfaceImplementations.Any (impl => impl.InterfaceType.Resolve (ctx).Equals (interfaceType))*/;
}
}
}
if (!alreadyImplemented)
toImplement.Add(new Tuple<IMember, bool>(prop, needsExplicitly));
}
if (!alreadyImplemented)
toImplement.Add(new Tuple<IMember, bool>(prop, needsExplicitly));
}
return toImplement;
}
static bool CompareMethods (IMethod interfaceMethod, IMethod typeMethod)
internal static bool CompareMethods(IMethod interfaceMethod, IMethod typeMethod)
{
if (typeMethod.IsExplicitInterfaceImplementation)
return typeMethod.ImplementedInterfaceMembers.Any (m => m.Equals (interfaceMethod));
return SignatureComparer.Ordinal.Equals (interfaceMethod, typeMethod);
return typeMethod.ImplementedInterfaceMembers.Any(m => m.Equals(interfaceMethod));
return SignatureComparer.Ordinal.Equals(interfaceMethod, typeMethod);
}
}
}

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

@ -32,7 +32,7 @@ using System.Linq; @@ -32,7 +32,7 @@ using System.Linq;
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 IEnumerable<CodeAction> GetActions(RefactoringContext context)
@ -60,7 +60,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -60,7 +60,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
script.InsertWithCursor(
context.TranslateString("Implement Interface"),
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 @@ -178,7 +178,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
// Default implementation: do nothing
// 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)

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

@ -84,6 +84,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -84,6 +84,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
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);
}
@ -110,6 +112,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -110,6 +112,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
c = ImplicitConversion(resolveResult.Type, toType);
if (c.IsValid) return c;
if (resolveResult.Type.Kind == TypeKind.Dynamic)
return Conversion.ImplicitDynamicConversion;
c = AnonymousFunctionConversion(resolveResult, toType);
if (c.IsValid) return c;
c = MethodGroupConversion(resolveResult, toType);
@ -157,8 +161,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -157,8 +161,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return Conversion.ImplicitReferenceConversion;
if (IsBoxingConversion(fromType, toType))
return Conversion.BoxingConversion;
if (fromType.Kind == TypeKind.Dynamic)
return Conversion.ImplicitDynamicConversion;
if (ImplicitTypeParameterConversion(fromType, toType)) {
// Implicit type parameter conversions that aren't also
// reference conversions are considered to be boxing conversions
@ -469,7 +471,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -469,7 +471,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
bool IdentityOrVarianceConversion(IType s, IType t, int subtypeCheckNestingDepth)
{
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 pt = t as ParameterizedType;
if (ps != null && pt != null) {
@ -497,8 +501,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -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 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

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

@ -1618,6 +1618,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1618,6 +1618,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
throw new NotSupportedException("Invalid value for NameLookupMode");
}
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);
if (extensionMethods.Count > 0) {
return new MethodGroupResolveResult(target, identifier, EmptyList<MethodListWithDeclaringType>.Instance, typeArguments) {
@ -1755,7 +1759,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1755,7 +1759,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (method.TypeParameters.Count != typeArguments.Count)
continue;
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);
} else {
if (IsEligibleExtensionMethod(compilation, conversions, targetType, method, true, out inferredTypes)) {
@ -1896,15 +1900,37 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1896,15 +1900,37 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// C# 4.0 spec: §7.6.5
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;
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);
if (or.BestCandidate != null) {
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
return or.CreateResolveResult(mgrr.TargetResult);
} else {
@ -2039,10 +2065,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -2039,10 +2065,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
switch (target.Type.Kind) {
case TypeKind.Dynamic:
for (int i = 0; i < arguments.Length; i++) {
arguments[i] = Convert(arguments[i], SpecialType.Dynamic);
}
return new ArrayAccessResolveResult(SpecialType.Dynamic, target, arguments);
return new DynamicInvocationResolveResult(target, DynamicInvocationType.Indexing, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly());
case TypeKind.Array:
case TypeKind.Pointer:
@ -2052,9 +2075,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -2052,9 +2075,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
// §7.6.6.2 Indexer access
OverloadResolution or = CreateOverloadResolution(arguments, argumentNames);
MemberLookup lookup = CreateMemberLookup();
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);
if (or.BestCandidate != null) {
return or.CreateResolveResult(target);
@ -2105,16 +2140,35 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -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)
{
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);
MemberLookup lookup = CreateMemberLookup();
var allApplicable = (arguments.Any(a => a.Type.Kind == TypeKind.Dynamic) ? new List<IMethod>() : null);
foreach (IMethod ctor in type.GetConstructors()) {
if (lookup.IsAccessible(ctor, allowProtectedAccess))
or.AddCandidate(ctor);
if (lookup.IsAccessible(ctor, allowProtectedAccess)) {
var orErrors = or.AddCandidate(ctor);
if (allApplicable != null && OverloadResolution.IsApplicable(orErrors))
allApplicable.Add(ctor);
}
else
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) {
return or.CreateResolveResult(null, initializerStatements);
} else {

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

@ -45,24 +45,57 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -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>
/// Represents the result of an invocation of a member of a dynamic object.
/// </summary>
public class DynamicInvocationResolveResult : ResolveResult
{
/// <summary>
/// Target of the invocation (a dynamic object).
/// Target of the invocation. Can be a dynamic expression or a <see cref="MethodGroupResolveResult"/>.
/// </summary>
public readonly ResolveResult Target;
/// <summary>
/// Type of the invocation.
/// </summary>
public readonly DynamicInvocationType InvocationType;
/// <summary>
/// Arguments for the call.
/// </summary>
public readonly IList<DynamicInvocationArgument> Arguments;
public DynamicInvocationResolveResult(ResolveResult target, IList<DynamicInvocationArgument> arguments) : base(SpecialType.Dynamic) {
this.Target = target;
this.Arguments = arguments ?? EmptyList<DynamicInvocationArgument>.Instance;
/// <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.InvocationType = invocationType;
this.Arguments = arguments ?? EmptyList<DynamicInvocationArgument>.Instance;
this.InitializerStatements = initializerStatements ?? EmptyList<ResolveResult>.Instance;
}
public override string ToString()

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

@ -29,10 +29,32 @@ using ICSharpCode.NRefactory.TypeSystem.Implementation; @@ -29,10 +29,32 @@ using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// A method list that belongs to a declaring type.
/// </summary>
public class MethodListWithDeclaringType : List<IParameterizedMember>
{
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 {
get { return declaringType; }
}
@ -64,8 +86,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -64,8 +86,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
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)
throw new ArgumentNullException("methods");
this.targetResult = targetResult;
@ -85,7 +105,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -85,7 +105,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// Gets the type of the reference to the target object.
/// </summary>
public IType TargetType {
get { return targetResult.Type; }
get { return targetResult != null ? targetResult.Type : SpecialType.UnknownType; }
}
/// <summary>
@ -132,6 +152,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -132,6 +152,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// Gets all candidate extension methods.
/// Note: this includes candidates that are not eligible due to an inapplicable
/// this argument.
/// The candidates will only be specialized if the type arguments were provided explicitly.
/// </summary>
/// <remarks>
/// The results are stored in nested lists because they are grouped by using scope.
@ -155,6 +176,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -155,6 +176,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
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)
{
var result = new List<List<IMethod>>();

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

@ -938,6 +938,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -938,6 +938,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ScanChildren(parameterDeclaration);
if (resolverEnabled) {
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:
foreach (IParameter p in resolver.LocalVariables.OfType<IParameter>()) {
if (p.Name == name)
@ -1479,12 +1496,20 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1479,12 +1496,20 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ResolveResult rr = resolver.ResolveObjectCreation(type, arguments, argumentNames, false, initializerStatements);
if (arguments.Length == 1 && rr.Type.Kind == TypeKind.Delegate) {
// process conversion in case it's a delegate creation
ProcessConversionResult(objectCreateExpression.Arguments.Single(), rr as ConversionResolveResult);
// 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
// the same delegate creation.
return WrapResult(rr);
// Apply conversion to argument if it directly wraps the argument
// (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
// to the target method - otherwise FindReferencedEntities would produce two results for
// the same delegate creation.
return WrapResult(rr);
} else {
return rr;
}
} else {
// process conversions in all other cases
ProcessConversionsInInvocation(null, objectCreateExpression.Arguments, rr as CSharpInvocationResolveResult);
@ -3847,7 +3872,102 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -3847,7 +3872,102 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#region Documentation Reference
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
}

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

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

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

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

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

@ -17,8 +17,10 @@ @@ -17,8 +17,10 @@
// DEALINGS IN THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Documentation;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.TypeSystem
@ -38,6 +40,23 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -38,6 +40,23 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
// resolve ID string
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;
}
}

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

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

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

@ -17,9 +17,9 @@ @@ -17,9 +17,9 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.IO;
using System.Linq;
using System.Threading;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
@ -289,5 +289,41 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis @@ -289,5 +289,41 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusBefore(case2.Statements.First()));
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; @@ -28,10 +28,59 @@ using ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod;
namespace ICSharpCode.NRefactory.CSharp.CodeActions
{
[Ignore("FIXME!!")]
[TestFixture]
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()]
public void ExtractMethodResultStatementTest()
@ -91,7 +140,6 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -91,7 +140,6 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
");
}
[Ignore("FIXME!!")]
[Test()]
public void ExtractMethodStaticResultStatementTest()
{
@ -146,7 +194,6 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -146,7 +194,6 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
");
}
[Ignore("FIXME!!")]
[Test()]
public void ExtractMethodMultiVariableTest()
{
@ -164,7 +211,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -164,7 +211,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
", @"class TestClass
{
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;
k = j + member;
@ -185,7 +232,8 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -185,7 +232,8 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
[Test()]
public void TestBug607990()
{
Test<ExtractMethodAction>(@"class TestClass
Test<ExtractMethodAction>(@"using System;
class TestClass
{
void TestMethod ()
{
@ -193,7 +241,8 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -193,7 +241,8 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
obj1.ToString();->
}
}
", @"class TestClass
", @"using System;
class TestClass
{
static void NewMethod ()
{
@ -212,7 +261,6 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -212,7 +261,6 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
/// <summary>
/// Bug 616193 - Extract method passes param with does not exists any more in main method
/// </summary>
[Ignore("FIXME!!")]
[Test()]
public void TestBug616193()
{
@ -248,7 +296,6 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -248,7 +296,6 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
/// <summary>
/// Bug 616199 - Extract method forgets to return a local var which is used in main method
/// </summary>
[Ignore("FIXME!!")]
[Test()]
public void TestBug616199()
{
@ -269,7 +316,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -269,7 +316,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
}
void TestMethod ()
{
string z = NewMethod ();
var z = NewMethod ();
string ret = ""test1"" + z;
}
}
@ -331,8 +378,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -331,8 +378,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
");
}
[Ignore("FIXME!!")]
[Ignore("Fix me!")]
[Test()]
public void ExtractMethodMultiVariableWithLocalReturnVariableTest()
{
@ -352,7 +398,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -352,7 +398,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
", @"class TestClass
{
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;
k = j + member;

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

@ -29,12 +29,11 @@ using ICSharpCode.NRefactory.CSharp.Refactoring; @@ -29,12 +29,11 @@ using ICSharpCode.NRefactory.CSharp.Refactoring;
namespace ICSharpCode.NRefactory.CSharp.CodeActions
{
[Ignore("TODO")]
[TestFixture]
public class ImplementAbstractMembersTest : ContextActionTestBase
{
[Test()]
public void TestSimpleInterface()
public void TestSimpleBaseType()
{
Test<ImplementAbstractMembersAction>(@"abstract class Simple {
public abstract void FooBar (string foo, int bar);
@ -50,12 +49,13 @@ class Foo : $Simple @@ -50,12 +49,13 @@ class Foo : $Simple
class Foo : 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
}");
}
");
}
}

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

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

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

@ -56,7 +56,6 @@ class Foo : IDisposable @@ -56,7 +56,6 @@ class Foo : IDisposable
/// <summary>
/// Bug 663842 - Interface implementation does not include constraints
/// </summary>
[Ignore("TODO")]
[Test()]
public void TestBug663842()
{
@ -82,21 +81,21 @@ interface ITest { @@ -82,21 +81,21 @@ interface ITest {
class Foo : ITest
{
#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
{
throw new System.NotImplementedException ();
throw new NotImplementedException ();
}
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
{
throw new System.NotImplementedException ();
throw new NotImplementedException ();
}
#endregion
}
@ -206,7 +205,6 @@ class Foo : ITest @@ -206,7 +205,6 @@ class Foo : ITest
/// <summary>
/// Bug 3365 - MD cannot implement IEnumerable interface correctly - MD cannot implement IEnumerable interface correctly
/// </summary>
[Ignore("TODO")]
[Test()]
public void TestBug3365()
{
@ -238,20 +236,68 @@ public interface ITest : IA, IEnumerable @@ -238,20 +236,68 @@ public interface ITest : IA, IEnumerable
class Foo : ITest
{
#region ITest implementation
public bool GetEnumerator ()
#region IEnumerable implementation
public IEnumerator GetEnumerator ()
{
throw new System.NotImplementedException ();
throw new NotImplementedException ();
}
#endregion
#region IEnumerable implementation
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
#region IA implementation
bool IA.GetEnumerator ()
{
throw new System.NotImplementedException ();
throw new NotImplementedException ();
}
#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 @@ -105,9 +105,9 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
foreach (var node in nodes) {
InsertBefore(entity, node);
}
var t = new Task (() => {});
t.RunSynchronously ();
return t;
var tcs = new TaskCompletionSource<object> ();
tcs.SetResult (null);
return tcs.Task;
}
public override Task InsertWithCursor (string operation, ITypeDefinition parentType, IEnumerable<AstNode> nodes)
@ -121,9 +121,9 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -121,9 +121,9 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
InsertText (startOffset, output.Text);
output.RegisterTrackedSegments (this, startOffset);
}
var t = new Task (() => {});
t.RunSynchronously ();
return t;
var tcs = new TaskCompletionSource<object> ();
tcs.SetResult (null);
return tcs.Task;
}
void Rename (AstNode node, string newName)

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

@ -4572,7 +4572,7 @@ class Test @@ -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 ("Value2"), "field 'Value2' not found.");
}
@ -5241,7 +5241,7 @@ public class TestFoo @@ -5241,7 +5241,7 @@ public class TestFoo
public void TestBug4961()
{
CombinedProviderTest(
@"using System;
@"using System;
using System.Collections.Generic;
namespace EnumerationProblem
@ -5323,7 +5323,47 @@ $mc->$ @@ -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 @@ -592,7 +592,7 @@ class TestClass
}
}");
Assert.IsNotNull (provider, "provider was not created.");
Assert.AreEqual (6, provider.Count);
Assert.IsTrue (provider.Count > 0);
}
[Test()]

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

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Linq;
using System.Text;
using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Parser.Expression
@ -234,5 +235,19 @@ 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("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 { @@ -205,5 +205,19 @@ public class Form1 {
typeof(NamespaceDeclaration)
}, 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 @@ -132,5 +132,118 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.GeneralScope
Assert.AreEqual(PreProcessorDirectiveType.Pragma, ppd.Type);
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);
}
}
}

6
ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/EventDeclarationTests.cs

@ -70,9 +70,9 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers @@ -70,9 +70,9 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers
MemberName = "EventHandler"
},
Name = "MyEvent",
AddAccessor = new Accessor { Body = new BlockStatement() },
RemoveAccessor = new Accessor { Body = new BlockStatement() }
});
AddAccessor = new Accessor { Body = new BlockStatement() },
RemoveAccessor = new Accessor { Body = new BlockStatement() }
});
}
[Test]

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

@ -73,8 +73,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -73,8 +73,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
[Test]
public void DynamicIdentityConversions()
{
Assert.AreEqual(C.IdentityConversion, ImplicitConversion(typeof(object), typeof(ReflectionHelper.Dynamic)));
Assert.AreEqual(C.IdentityConversion, ImplicitConversion(typeof(ReflectionHelper.Dynamic), typeof(object)));
Assert.AreEqual(C.IdentityConversion, ImplicitConversion(typeof(object), typeof(dynamic)));
Assert.AreEqual(C.IdentityConversion, ImplicitConversion(typeof(dynamic), typeof(object)));
}
[Test]
@ -155,12 +155,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -155,12 +155,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
[Test]
public void SimpleDynamicConversions()
public void ConversionToDynamic()
{
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.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]
@ -512,7 +524,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -512,7 +524,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
[Test]
public void ExplicitUserDefinedConversion() {
public void ExplicitUserDefinedConversion()
{
var rr = Resolve<ConversionResolveResult>(@"
class C1 {}
class C2 {
@ -529,5 +542,29 @@ class C { @@ -529,5 +542,29 @@ class C {
Assert.IsTrue(rr.Conversion.IsUserDefined);
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 @@ @@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
@ -37,6 +38,7 @@ class TestClass { @@ -37,6 +38,7 @@ class TestClass {
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
Assert.That(rr.Target, Is.InstanceOf<DynamicMemberResolveResult>());
var dynamicMember = (DynamicMemberResolveResult)rr.Target;
Assert.That(dynamicMember.Target is LocalResolveResult && ((LocalResolveResult)dynamicMember.Target).Variable.Name == "obj");
@ -61,6 +63,7 @@ class TestClass { @@ -61,6 +63,7 @@ class TestClass {
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
Assert.That(rr.Target, Is.InstanceOf<DynamicMemberResolveResult>());
var dynamicMember = (DynamicMemberResolveResult)rr.Target;
Assert.That(dynamicMember.Target is LocalResolveResult && ((LocalResolveResult)dynamicMember.Target).Variable.Name == "obj");
@ -86,12 +89,14 @@ class TestClass { @@ -86,12 +89,14 @@ class TestClass {
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation));
Assert.That(rr.Target, Is.InstanceOf<DynamicInvocationResolveResult>());
var innerInvocation = (DynamicInvocationResolveResult)rr.Target;
Assert.That(innerInvocation.Target, Is.InstanceOf<DynamicMemberResolveResult>());
var dynamicMember = (DynamicMemberResolveResult)innerInvocation.Target;
Assert.That(dynamicMember.Target is LocalResolveResult && ((LocalResolveResult)dynamicMember.Target).Variable.Name == "obj");
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[0].Name, Is.Null);
Assert.That(innerInvocation.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)innerInvocation.Arguments[0].Value).Variable.Name == "a");
@ -99,5 +104,612 @@ class TestClass { @@ -99,5 +104,612 @@ class TestClass {
Assert.That(rr.Arguments[0].Name, Is.Null);
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 @@ @@ -17,8 +17,10 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Resolver
@ -118,5 +120,120 @@ public static class XC { @@ -118,5 +120,120 @@ public static class XC {
Assert.AreEqual(1, inferredTypes.Length);
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() { @@ -275,5 +275,46 @@ class Test<T> where T : new() {
Assert.AreEqual(TypeKind.TypeParameter, rr.Type.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 @@ -148,6 +148,30 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
out 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
#region Inference with Method Groups

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

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

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

@ -25,7 +25,6 @@ using NUnit.Framework; @@ -25,7 +25,6 @@ using NUnit.Framework;
namespace ICSharpCode.NRefactory.Documentation
{
[TestFixture]
[Ignore("Cref parsing not yet implemented")]
public class CSharpCrefParserTests
{
[Test]
@ -39,6 +38,7 @@ namespace ICSharpCode.NRefactory.Documentation @@ -39,6 +38,7 @@ namespace ICSharpCode.NRefactory.Documentation
}
[Test]
[Ignore("mcs bug")]
public void This()
{
ParseUtilCSharp.AssertDocumentationReference(
@ -49,6 +49,7 @@ namespace ICSharpCode.NRefactory.Documentation @@ -49,6 +49,7 @@ namespace ICSharpCode.NRefactory.Documentation
}
[Test]
[Ignore("mcs bug (Unexpected symbol `this', expecting `explicit', `implicit', `operator', or `type')")]
public void ThisWithParameter()
{
ParseUtilCSharp.AssertDocumentationReference(
@ -115,6 +116,21 @@ namespace ICSharpCode.NRefactory.Documentation @@ -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]
public void Generic()
{
@ -201,6 +217,7 @@ namespace ICSharpCode.NRefactory.Documentation @@ -201,6 +217,7 @@ namespace ICSharpCode.NRefactory.Documentation
}
[Test]
[Ignore("mcs bug (Unexpected symbol `operator', expecting `identifier' or `this')")]
public void OperatorPlusWithDeclaringType()
{
ParseUtilCSharp.AssertDocumentationReference(
@ -256,6 +273,7 @@ namespace ICSharpCode.NRefactory.Documentation @@ -256,6 +273,7 @@ namespace ICSharpCode.NRefactory.Documentation
}
[Test]
[Ignore("mcs bug (Unexpected symbol `explicit', expecting `identifier' or `this')")]
public void ExplicitOperatorWithParameterListAndDeclaringType()
{
ParseUtilCSharp.AssertDocumentationReference(

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

@ -21,6 +21,7 @@ using System.Collections; @@ -21,6 +21,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using NUnit.Framework;
@ -31,12 +32,43 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -31,12 +32,43 @@ namespace ICSharpCode.NRefactory.TypeSystem
[TestFixture]
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;
[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)
@ -46,7 +78,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -46,7 +78,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
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)
@ -58,24 +90,26 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -58,24 +90,26 @@ namespace ICSharpCode.NRefactory.TypeSystem
public void ObjectBaseTypes()
{
Assert.AreEqual(GetTypes(typeof(object)), GetAllBaseTypes(typeof(object)));
Assert.That(compilation.FindType(KnownTypeCode.Object).DirectBaseTypes, Is.Empty);
}
[Test]
public void StringBaseTypes()
{
Assert.AreEqual(GetTypes(typeof(string), typeof(object), typeof(IComparable), typeof(ICloneable), typeof(IConvertible),
typeof(IComparable<string>), typeof(IEquatable<string>), typeof(IEnumerable<char>), typeof(IEnumerable)),
Assert.AreEqual(GetTypes(typeof(string), typeof(object),
typeof(IComparable<string>), typeof(IEnumerable<char>), typeof(IEnumerable)),
GetAllBaseTypes(typeof(string)));
}
[Test]
[Ignore("Produces different results in .NET 4.5 due to new read-only interfaces")]
public void ArrayOfString()
{
Assert.AreEqual(GetTypes(typeof(string[]), typeof(Array), typeof(object),
typeof(IList), typeof(ICollection), typeof(IEnumerable),
typeof(IList<string>), typeof(ICollection<string>), typeof(IEnumerable<string>),
typeof(IStructuralEquatable), typeof(IStructuralComparable), typeof(ICloneable)),
var expectedTypes = GetTypes(
typeof(string[]), typeof(Array), typeof(object),
typeof(IList), typeof(ICollection), typeof(IEnumerable), typeof(ICloneable),
typeof(IList<string>), typeof(ICollection<string>), typeof(IEnumerable<string>));
Assert.AreEqual(expectedTypes,
GetAllBaseTypes(typeof(string[])));
}
@ -83,8 +117,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -83,8 +117,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
public unsafe void ArrayOfPointers()
{
Assert.AreEqual(GetTypes(typeof(int*[]), typeof(Array), typeof(object),
typeof(IList), typeof(ICollection), typeof(IEnumerable),
typeof(IStructuralEquatable), typeof(IStructuralComparable), typeof(ICloneable)),
typeof(IList), typeof(ICollection), typeof(IEnumerable), typeof(ICloneable)),
GetAllBaseTypes(typeof(int*[])));
}
@ -92,8 +125,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -92,8 +125,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
public void MultidimensionalArrayOfString()
{
Assert.AreEqual(GetTypes(typeof(string[,]), typeof(Array), typeof(object),
typeof(IList), typeof(ICollection), typeof(IEnumerable),
typeof(IStructuralEquatable), typeof(IStructuralComparable), typeof(ICloneable)),
typeof(IList), typeof(ICollection), typeof(IEnumerable), typeof(ICloneable)),
GetAllBaseTypes(typeof(string[,])));
}
@ -175,7 +207,6 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -175,7 +207,6 @@ namespace ICSharpCode.NRefactory.TypeSystem
}
[Test]
[Ignore("Produces different results in .NET 4.5 due to new read-only interfaces")]
public void BaseTypesOfListOfString()
{
Assert.AreEqual(
@ -186,7 +217,6 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -186,7 +217,6 @@ namespace ICSharpCode.NRefactory.TypeSystem
}
[Test]
[Ignore("Produces different results in .NET 4.5 due to new read-only interfaces")]
public void BaseTypesOfUnboundDictionary()
{
Assert.AreEqual(
@ -198,15 +228,12 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -198,15 +228,12 @@ namespace ICSharpCode.NRefactory.TypeSystem
typeof(ICollection).FullName,
typeof(IDictionary).FullName,
typeof(IEnumerable).FullName,
typeof(object).FullName,
typeof(IDeserializationCallback).FullName,
typeof(ISerializable).FullName,
typeof(object).FullName
},
GetAllBaseTypes(typeof(Dictionary<,>)).Select(t => t.ReflectionName).ToArray());
GetAllBaseTypes(typeof(Dictionary<,>)).Select(t => t.ReflectionName).OrderBy(n => n).ToArray());
}
[Test]
[Ignore("Produces different results in .NET 4.5 due to new read-only interfaces")]
public void BaseTypeDefinitionsOfListOfString()
{
Assert.AreEqual(
@ -217,12 +244,10 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -217,12 +244,10 @@ namespace ICSharpCode.NRefactory.TypeSystem
}
[Test]
[Ignore("Produces different results in .NET 4.5 due to new read-only interfaces")]
public void BaseTypeDefinitionsOfStringArray()
{
Assert.AreEqual(
GetTypes(typeof(Array), typeof(object),
typeof(ICloneable), typeof(IStructuralComparable), typeof(IStructuralEquatable),
GetTypes(typeof(Array), typeof(object), typeof(ICloneable),
typeof(IList), typeof(ICollection), typeof(IEnumerable),
typeof(IEnumerable<>), typeof(ICollection<>), typeof(IList<>)),
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 @@ -44,6 +44,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase
public class ParamsAttribute : Attribute
{
public ParamsAttribute(params object[] x) {}
[Params(Property = new string[] { "a", "b" })]
public string[] Property { get; set; }
}
[Double(1)]
@ -291,4 +294,18 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase @@ -291,4 +294,18 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase
public class ClassThatImplementsEventExplicitly : IHasEvent {
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 @@ -821,6 +821,23 @@ namespace ICSharpCode.NRefactory.TypeSystem
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]
public void DoubleAttribute_ImplicitNumericConversion()
{
@ -978,6 +995,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -978,6 +995,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
public void ExplicitIndexerImplementationReturnsTheCorrectMembers() {
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.Getter.ImplementedInterfaceMembers.Count == 1));
Assert.That(type.Properties.All(p => p.Setter.ImplementedInterfaceMembers.Count == 1));
@ -1094,5 +1112,25 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -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.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; @@ -23,4 +23,4 @@ using System.Runtime.InteropServices;
// [AssemblyFileVersion] is the version of the NuGet package,
// 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 @@ -185,6 +185,14 @@ namespace ICSharpCode.NRefactory.Semantics
get { return type == 0; }
}
public override bool IsNullLiteralConversion {
get { return type == 1; }
}
public override bool IsConstantExpressionConversion {
get { return type == 2; }
}
public override bool IsReferenceConversion {
get { return type == 3; }
}
@ -365,6 +373,14 @@ namespace ICSharpCode.NRefactory.Semantics @@ -365,6 +373,14 @@ namespace ICSharpCode.NRefactory.Semantics
get { return false; }
}
public virtual bool IsNullLiteralConversion {
get { return false; }
}
public virtual bool IsConstantExpressionConversion {
get { return false; }
}
public virtual bool IsNumericConversion {
get { return false; }
}

2
ICSharpCode.NRefactory/Semantics/MemberResolveResult.cs

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

95
ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs

@ -99,6 +99,21 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -99,6 +99,21 @@ namespace ICSharpCode.NRefactory.TypeSystem
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
/// <summary>
/// Loads the assembly definition into a project content.
@ -124,6 +139,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -124,6 +139,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
}
this.currentAssembly = new CecilUnresolvedAssembly(assemblyDefinition.Name.Name, this.DocumentationProvider);
currentAssembly.Location = assemblyDefinition.MainModule.FullyQualifiedName;
currentAssembly.AssemblyAttributes.AddRange(assemblyAttributes);
currentAssembly.ModuleAttributes.AddRange(assemblyAttributes);
@ -133,13 +149,15 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -133,13 +149,15 @@ namespace ICSharpCode.NRefactory.TypeSystem
int typeParameterCount;
string name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name, out typeParameterCount);
var typeRef = new GetClassTypeReference(GetAssemblyReference(type.Scope), type.Namespace, name, typeParameterCount);
typeRef = this.InterningProvider.Intern(typeRef);
if (this.InterningProvider != null)
typeRef = this.InterningProvider.Intern(typeRef);
var key = new FullNameAndTypeParameterCount(type.Namespace, name, typeParameterCount);
currentAssembly.AddTypeForwarder(key, typeRef);
}
}
// Create and register all types:
CecilLoader cecilLoaderCloneForLazyLoading = LazyLoad ? new CecilLoader(this) : null;
List<TypeDefinition> cecilTypeDefs = new List<TypeDefinition>();
List<DefaultUnresolvedTypeDefinition> typeDefs = new List<DefaultUnresolvedTypeDefinition>();
foreach (ModuleDefinition module in assemblyDefinition.Modules) {
@ -150,10 +168,14 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -150,10 +168,14 @@ namespace ICSharpCode.NRefactory.TypeSystem
if (name.Length == 0)
continue;
var t = CreateTopLevelTypeDefinition(td);
cecilTypeDefs.Add(td);
typeDefs.Add(t);
currentAssembly.AddTypeDefinition(t);
if (this.LazyLoad) {
currentAssembly.AddTypeDefinition(new LazyCecilTypeDefinition(cecilLoaderCloneForLazyLoading, td));
} else {
var t = CreateTopLevelTypeDefinition(td);
cecilTypeDefs.Add(td);
typeDefs.Add(t);
currentAssembly.AddTypeDefinition(t);
}
}
}
}
@ -162,8 +184,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -162,8 +184,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
InitTypeDefinition(cecilTypeDefs[i], typeDefs[i]);
}
if (HasCecilReferences)
typeSystemTranslationTable[this.currentAssembly] = assemblyDefinition;
RegisterCecilObject(this.currentAssembly, assemblyDefinition);
var result = this.currentAssembly;
this.currentAssembly = null;
@ -229,8 +250,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -229,8 +250,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
var param = new ReaderParameters { AssemblyResolver = new DummyAssemblyResolver() };
AssemblyDefinition asm = AssemblyDefinition.ReadAssembly(fileName, param);
var result = LoadAssembly(asm);
if (HasCecilReferences)
typeSystemTranslationTable[result] = asm;
RegisterCecilObject(result, asm);
return result;
}
@ -1175,7 +1195,8 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -1175,7 +1195,8 @@ namespace ICSharpCode.NRefactory.TypeSystem
public KeyValuePair<IMember, ResolveResult> ReadNamedArg(IType attributeType)
{
EntityType memberType;
switch (ReadByte()) {
var b = ReadByte();
switch (b) {
case 0x53:
memberType = EntityType.Field;
break;
@ -1183,7 +1204,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -1183,7 +1204,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
memberType = EntityType.Property;
break;
default:
throw new NotSupportedException();
throw new NotSupportedException(string.Format("Custom member type 0x{0:x} is not supported.", b));
}
IType type = ReadCustomAttributeFieldOrPropType();
string name = ReadSerString();
@ -1499,12 +1520,11 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -1499,12 +1520,11 @@ namespace ICSharpCode.NRefactory.TypeSystem
td.AddDefaultConstructorIfRequired = (td.Kind == TypeKind.Struct || td.Kind == TypeKind.Enum);
InitMembers(typeDefinition, td, td.Members);
if (HasCecilReferences)
typeSystemTranslationTable[td] = typeDefinition;
if (this.InterningProvider != null) {
td.ApplyInterningProvider(this.InterningProvider);
}
td.Freeze();
RegisterCecilObject(td, typeDefinition);
}
void InitBaseTypes(TypeDefinition typeDefinition, IList<ITypeReference> baseTypes)
@ -1656,7 +1676,18 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -1656,7 +1676,18 @@ namespace ICSharpCode.NRefactory.TypeSystem
bool getterVisible = property.GetMethod != null && IsVisible(property.GetMethod.Attributes);
bool setterVisible = property.SetMethod != null && IsVisible(property.SetMethod.Attributes);
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));
}
}
@ -1707,12 +1738,11 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -1707,12 +1738,11 @@ namespace ICSharpCode.NRefactory.TypeSystem
loader.AddAttributes(typeDefinition, this);
flags[FlagHasExtensionMethods] = HasExtensionAttribute(typeDefinition);
if (loader.HasCecilReferences)
loader.typeSystemTranslationTable[this] = typeDefinition;
if (loader.InterningProvider != null) {
this.ApplyInterningProvider(loader.InterningProvider);
}
this.Freeze();
loader.RegisterCecilObject(this, typeDefinition);
}
public override string Namespace {
@ -1720,6 +1750,15 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -1720,6 +1750,15 @@ namespace ICSharpCode.NRefactory.TypeSystem
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 {
get { return kind; }
}
@ -2123,14 +2162,24 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -2123,14 +2162,24 @@ namespace ICSharpCode.NRefactory.TypeSystem
void FinishReadMember(AbstractUnresolvedMember member, object cecilDefinition)
{
member.ApplyInterningProvider(this.InterningProvider);
if (this.InterningProvider != null)
member.ApplyInterningProvider(this.InterningProvider);
member.Freeze();
if (HasCecilReferences)
typeSystemTranslationTable[member] = cecilDefinition;
RegisterCecilObject(member, cecilDefinition);
}
#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
{
@ -2139,8 +2188,10 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -2139,8 +2188,10 @@ namespace ICSharpCode.NRefactory.TypeSystem
if (!HasCecilReferences)
throw new NotSupportedException ("This instance contains no cecil references.");
object result;
if (!typeSystemTranslationTable.TryGetValue (typeSystemObject, out result))
return null;
lock (typeSystemTranslationTable) {
if (!typeSystemTranslationTable.TryGetValue (typeSystemObject, out result))
return null;
}
return result as T;
}

6
ICSharpCode.NRefactory/TypeSystem/IAssembly.cs

@ -31,6 +31,12 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -31,6 +31,12 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// </summary>
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>
/// Gets the list of all assembly attributes in the project.
/// </summary>

5
ICSharpCode.NRefactory/TypeSystem/INamespace.cs

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

5
ICSharpCode.NRefactory/TypeSystem/IProjectContent.cs

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

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

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

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

@ -19,6 +19,8 @@ @@ -19,6 +19,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICSharpCode.NRefactory.Semantics;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
@ -217,6 +219,29 @@ 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>
/// Gets a dummy constructor for the specified compilation.
/// </summary>

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

@ -70,6 +70,17 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -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 {
get { return assemblyAttributes; }
}
@ -367,6 +378,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -367,6 +378,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
get { return parentNamespace; }
}
IEnumerable<IAssembly> INamespace.ContributingAssemblies {
get { return new [] { assembly }; }
}
IEnumerable<INamespace> INamespace.ChildNamespaces {
get { return childNamespaces; }
}

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

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

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

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

4
Packages/ICSharpCode.NRefactory.nuspec

@ -2,9 +2,9 @@ @@ -2,9 +2,9 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>ICSharpCode.NRefactory</id>
<version>5.0.1</version>
<version>5.1.0</version>
<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>
<licenseUrl>http://www.opensource.org/licenses/mit-license.php</licenseUrl>
<projectUrl>https://github.com/icsharpcode/NRefactory/</projectUrl>

Loading…
Cancel
Save