From 284ddfadf1a34b506e5fb4f49be92f4bc3262a7d Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 26 Nov 2016 00:25:24 +0100 Subject: [PATCH] Phase 2: Merge ICSharpCode.NRefactory into ICSharpCode.Decompiler --- .../CSharp/Analysis/ControlFlow.cs | 96 +- .../Analysis/DefiniteAssignmentAnalysis.cs | 4 +- .../CSharp/Ast/IAnnotatable.cs | 252 +++ .../CSharp/Ast/PatternMatching/AnyNode.cs | 47 + .../Ast/PatternMatching/AnyNodeOrNull.cs | 58 + .../Ast/PatternMatching/Backreference.cs | 50 + .../Ast/PatternMatching/BacktrackingInfo.cs | 32 + .../CSharp/Ast/PatternMatching/Choice.cs | 68 + .../CSharp/Ast/PatternMatching/INode.cs | 69 + .../CSharp/Ast/PatternMatching/Match.cs | 100 ++ .../CSharp/Ast/PatternMatching/NamedNode.cs | 53 + .../Ast/PatternMatching/OptionalNode.cs | 58 + .../CSharp/Ast/PatternMatching/Pattern.cs | 114 ++ .../CSharp/Ast/PatternMatching/Repeat.cs | 74 + ICSharpCode.Decompiler/CSharp/Ast/Role.cs | 113 ++ .../CSharp/Ast/TextLocation.cs | 223 +++ .../Documentation/DocumentationComment.cs | 95 ++ .../GetPotentiallyNestedClassTypeReference.cs | 71 + .../Documentation/IDocumentationProvider.cs | 51 + .../Documentation/IdStringMemberReference.cs | 77 + .../Documentation/IdStringProvider.cs | 393 +++++ .../Documentation/XmlDocumentationProvider.cs | 422 +++++ ICSharpCode.Decompiler/Editor/IDocument.cs | 205 +++ .../Editor/IDocumentLine.cs | 60 + ICSharpCode.Decompiler/Editor/ISegment.cs | 71 + ICSharpCode.Decompiler/Editor/ITextAnchor.cs | 139 ++ .../Editor/ITextPasteHandler.cs | 51 + ICSharpCode.Decompiler/Editor/ITextSource.cs | 218 +++ .../Editor/ReadOnlyDocument.cs | 447 ++++++ .../Editor/StringBuilderDocument.cs | 493 ++++++ .../Editor/StringTextSource.cs | 160 ++ .../Editor/TextChangeEventArgs.cs | 118 ++ .../Editor/TextSourceVersionProvider.cs | 130 ++ .../Editor/UnicodeNewline.cs | 365 +++++ .../FlowAnalysis/ControlFlowNode.cs | 58 +- .../ICSharpCode.Decompiler.csproj | 203 ++- .../Semantics/AmbiguousResolveResult.cs | 51 + .../Semantics/ArrayAccessResolveResult.cs | 50 + .../Semantics/ArrayCreateResolveResult.cs | 60 + .../Semantics/ByReferenceResolveResult.cs | 66 + .../Semantics/ConstantResolveResult.cs | 55 + .../Semantics/Conversion.cs | 568 +++++++ .../Semantics/ConversionResolveResult.cs | 68 + .../Semantics/ErrorResolveResult.cs | 56 + .../Semantics/ForEachResolveResult.cs | 90 ++ .../InitializedObjectResolveResult.cs | 34 + .../Semantics/InvocationResolveResult.cs | 75 + .../Semantics/LocalResolveResult.cs | 77 + .../Semantics/MemberResolveResult.cs | 148 ++ .../Semantics/NamedArgumentResolveResult.cs | 81 + .../Semantics/NamespaceResolveResult.cs | 50 + .../Semantics/OperatorResolveResult.cs | 90 ++ .../Semantics/ResolveResult.cs | 78 + .../Semantics/SizeOfResolveResult.cs | 66 + .../Semantics/ThisResolveResult.cs | 44 + .../Semantics/TypeIsResolveResult.cs | 47 + .../Semantics/TypeOfResolveResult.cs | 46 + .../Semantics/TypeResolveResult.cs | 47 + .../Semantics/UnknownMemberResolveResult.cs | 122 ++ .../Tests/ICSharpCode.Decompiler.Tests.csproj | 4 - .../TypeSystem/Accessibility.cs | 117 ++ .../TypeSystem/AnonymousType.cs | 221 +++ .../TypeSystem/ArrayType.cs | 200 +++ .../TypeSystem/AssemblyLoader.cs | 94 ++ .../TypeSystem/AssemblyQualifiedTypeName.cs | 79 + .../TypeSystem/ByReferenceType.cs | 112 ++ .../TypeSystem/ComHelper.cs | 63 + .../TypeSystem/DefaultSolutionSnapshot.cs | 86 ++ .../TypeSystem/DomRegion.cs | 230 +++ .../TypeSystem/EntityType.cs | 63 + ICSharpCode.Decompiler/TypeSystem/Error.cs | 139 ++ .../TypeSystem/FullTypeName.cs | 315 ++++ .../TypeSystem/IAmbience.cs | 107 ++ .../TypeSystem/IAssembly.cs | 128 ++ .../TypeSystem/IAttribute.cs | 75 + .../TypeSystem/ICodeContext.cs | 38 + .../TypeSystem/ICompilation.cs | 91 ++ .../TypeSystem/IConstantValue.cs | 38 + ICSharpCode.Decompiler/TypeSystem/IEntity.cs | 178 +++ ICSharpCode.Decompiler/TypeSystem/IEvent.cs | 58 + ICSharpCode.Decompiler/TypeSystem/IField.cs | 99 ++ .../TypeSystem/IFreezable.cs | 35 + .../TypeSystem/IInterningProvider.cs | 102 ++ ICSharpCode.Decompiler/TypeSystem/IMember.cs | 196 +++ ICSharpCode.Decompiler/TypeSystem/IMethod.cs | 168 ++ .../TypeSystem/INamedElement.cs | 66 + .../TypeSystem/INamespace.cs | 88 ++ .../TypeSystem/IParameter.cs | 104 ++ .../TypeSystem/IParameterizedMember.cs | 40 + .../TypeSystem/IProjectContent.cs | 159 ++ .../TypeSystem/IProperty.cs | 62 + .../TypeSystem/ISolutionSnapshot.cs | 43 + .../TypeSystem/ISupportsInterning.cs | 39 + ICSharpCode.Decompiler/TypeSystem/ISymbol.cs | 100 ++ ICSharpCode.Decompiler/TypeSystem/IType.cs | 350 +++++ .../TypeSystem/ITypeDefinition.cs | 170 ++ .../TypeSystem/ITypeParameter.cs | 151 ++ .../TypeSystem/ITypeReference.cs | 73 + .../TypeSystem/IUnresolvedFile.cs | 80 + .../TypeSystem/IVariable.cs | 54 + .../Implementation/AbstractFreezable.cs | 110 ++ .../Implementation/AbstractResolvedEntity.cs | 124 ++ .../Implementation/AbstractResolvedMember.cs | 168 ++ .../AbstractResolvedTypeParameter.cs | 412 +++++ .../TypeSystem/Implementation/AbstractType.cs | 180 +++ .../AbstractUnresolvedEntity.cs | 334 ++++ .../AbstractUnresolvedMember.cs | 272 ++++ .../AccessorOwnerMemberReference.cs | 56 + .../Implementation/BaseTypeCollector.cs | 75 + .../TypeSystem/Implementation/BlobReader.cs | 387 +++++ .../DefaultAssemblyReference.cs | 87 ++ .../Implementation/DefaultAttribute.cs | 97 ++ .../Implementation/DefaultMemberReference.cs | 118 ++ .../Implementation/DefaultParameter.cs | 202 +++ .../Implementation/DefaultResolvedEvent.cs | 75 + .../Implementation/DefaultResolvedField.cs | 93 ++ .../Implementation/DefaultResolvedMethod.cs | 327 ++++ .../Implementation/DefaultResolvedProperty.cs | 114 ++ .../DefaultResolvedTypeDefinition.cs | 963 ++++++++++++ .../DefaultResolvedTypeParameter.cs | 257 +++ .../DefaultUnresolvedAssembly.cs | 575 +++++++ .../DefaultUnresolvedAttribute.cs | 283 ++++ .../Implementation/DefaultUnresolvedEvent.cs | 99 ++ .../Implementation/DefaultUnresolvedField.cs | 97 ++ .../Implementation/DefaultUnresolvedMethod.cs | 287 ++++ .../DefaultUnresolvedParameter.cs | 275 ++++ .../DefaultUnresolvedProperty.cs | 126 ++ .../DefaultUnresolvedTypeDefinition.cs | 240 +++ .../DefaultUnresolvedTypeParameter.cs | 194 +++ .../Implementation/DefaultVariable.cs | 109 ++ .../Implementation/DummyTypeParameter.cs | 217 +++ ...tInterfaceImplementationMemberReference.cs | 80 + .../FullNameAndTypeParameterCount.cs | 28 + .../Implementation/GetClassTypeReference.cs | 158 ++ .../Implementation/GetMembersHelper.cs | 296 ++++ .../Implementation/KnownTypeCache.cs | 60 + .../Implementation/MergedNamespace.cs | 164 ++ .../Implementation/MinimalCorlib.cs | 65 + .../Implementation/NestedTypeReference.cs | 106 ++ .../Implementation/ResolvedAttributeBlob.cs | 176 +++ .../Implementation/SimpleCompilation.cs | 168 ++ .../Implementation/SimpleConstantValue.cs | 69 + .../Implementation/SimpleInterningProvider.cs | 143 ++ .../Implementation/SpecializedEvent.cs | 63 + .../Implementation/SpecializedField.cs | 61 + .../Implementation/SpecializedMember.cs | 409 +++++ .../Implementation/SpecializedMethod.cs | 286 ++++ .../Implementation/SpecializedProperty.cs | 59 + .../SpecializingMemberReference.cs | 67 + .../Implementation/TypeParameterReference.cs | 96 ++ .../Implementation/TypeWithElementType.cs | 61 + .../TypeSystem/Implementation/UnknownType.cs | 117 ++ .../Implementation/UnresolvedAttributeBlob.cs | 78 + .../UnresolvedSecurityDeclarationBlob.cs | 152 ++ .../Implementation/VoidTypeDefinition.cs | 73 + .../TypeSystem/InheritanceHelper.cs | 152 ++ .../TypeSystem/IntersectionType.cs | 178 +++ .../TypeSystem/KnownTypeReference.cs | 500 ++++++ .../TypeSystem/NullableType.cs | 87 ++ .../TypeSystem/ParameterListComparer.cs | 168 ++ .../TypeSystem/ParameterizedType.cs | 436 ++++++ .../TypeSystem/PointerType.cs | 113 ++ .../TypeSystem/ProjectReference.cs | 56 + .../TypeSystem/ReflectionHelper.cs | 424 +++++ .../ReflectionNameParseException.cs | 63 + .../TypeSystem/SimpleTypeResolveContext.cs | 92 ++ .../TypeSystem/SpecialType.cs | 106 ++ ICSharpCode.Decompiler/TypeSystem/TaskType.cs | 78 + .../TypeSystem/TopLevelTypeName.cs | 144 ++ ICSharpCode.Decompiler/TypeSystem/TypeKind.cs | 86 ++ .../TypeSystem/TypeParameterSubstitution.cs | 193 +++ .../TypeSystem/TypeSystemExtensions.cs | 790 ++++++++++ .../TypeSystem/TypeVisitor.cs | 63 + .../Util/7BitEncodedInts.cs | 123 ++ ICSharpCode.Decompiler/Util/BitVector16.cs | 83 + ICSharpCode.Decompiler/Util/BusyManager.cs | 73 + .../Util/CSharpPrimitiveCast.cs | 431 ++++++ ICSharpCode.Decompiler/Util/CacheManager.cs | 59 + .../Util/CallbackOnDispose.cs | 51 + ICSharpCode.Decompiler/Util/EmptyList.cs | 118 ++ .../Util/ExtensionMethods.cs | 44 + ICSharpCode.Decompiler/Util/FastSerializer.cs | 1371 +++++++++++++++++ ICSharpCode.Decompiler/Util/ImmutableStack.cs | 132 ++ ICSharpCode.Decompiler/Util/LazyInit.cs | 48 + .../Util/MultiDictionary.cs | 154 ++ ICSharpCode.Decompiler/Util/Platform.cs | 40 + ICSharpCode.Decompiler/Util/ProjectedList.cs | 239 +++ .../Util/ReferenceComparer.cs | 39 + ICSharpCode.Decompiler/Util/TreeTraversal.cs | 112 ++ .../ILSpy.BamlDecompiler.csproj | 4 - ILSpy/ILSpy.csproj | 4 - 191 files changed, 28665 insertions(+), 99 deletions(-) create mode 100644 ICSharpCode.Decompiler/CSharp/Ast/IAnnotatable.cs create mode 100644 ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/AnyNode.cs create mode 100644 ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/AnyNodeOrNull.cs create mode 100644 ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Backreference.cs create mode 100644 ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/BacktrackingInfo.cs create mode 100644 ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Choice.cs create mode 100644 ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/INode.cs create mode 100644 ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Match.cs create mode 100644 ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/NamedNode.cs create mode 100644 ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/OptionalNode.cs create mode 100644 ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Pattern.cs create mode 100644 ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Repeat.cs create mode 100644 ICSharpCode.Decompiler/CSharp/Ast/Role.cs create mode 100644 ICSharpCode.Decompiler/CSharp/Ast/TextLocation.cs create mode 100644 ICSharpCode.Decompiler/Documentation/DocumentationComment.cs create mode 100644 ICSharpCode.Decompiler/Documentation/GetPotentiallyNestedClassTypeReference.cs create mode 100644 ICSharpCode.Decompiler/Documentation/IDocumentationProvider.cs create mode 100644 ICSharpCode.Decompiler/Documentation/IdStringMemberReference.cs create mode 100644 ICSharpCode.Decompiler/Documentation/IdStringProvider.cs create mode 100644 ICSharpCode.Decompiler/Documentation/XmlDocumentationProvider.cs create mode 100644 ICSharpCode.Decompiler/Editor/IDocument.cs create mode 100644 ICSharpCode.Decompiler/Editor/IDocumentLine.cs create mode 100644 ICSharpCode.Decompiler/Editor/ISegment.cs create mode 100644 ICSharpCode.Decompiler/Editor/ITextAnchor.cs create mode 100644 ICSharpCode.Decompiler/Editor/ITextPasteHandler.cs create mode 100644 ICSharpCode.Decompiler/Editor/ITextSource.cs create mode 100644 ICSharpCode.Decompiler/Editor/ReadOnlyDocument.cs create mode 100644 ICSharpCode.Decompiler/Editor/StringBuilderDocument.cs create mode 100644 ICSharpCode.Decompiler/Editor/StringTextSource.cs create mode 100644 ICSharpCode.Decompiler/Editor/TextChangeEventArgs.cs create mode 100644 ICSharpCode.Decompiler/Editor/TextSourceVersionProvider.cs create mode 100644 ICSharpCode.Decompiler/Editor/UnicodeNewline.cs create mode 100644 ICSharpCode.Decompiler/Semantics/AmbiguousResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/ArrayAccessResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/ArrayCreateResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/ByReferenceResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/ConstantResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/Conversion.cs create mode 100644 ICSharpCode.Decompiler/Semantics/ConversionResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/ErrorResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/ForEachResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/InitializedObjectResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/InvocationResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/LocalResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/MemberResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/NamedArgumentResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/NamespaceResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/OperatorResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/ResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/SizeOfResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/ThisResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/TypeIsResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/TypeOfResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/TypeResolveResult.cs create mode 100644 ICSharpCode.Decompiler/Semantics/UnknownMemberResolveResult.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Accessibility.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/AnonymousType.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/ArrayType.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/AssemblyLoader.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/AssemblyQualifiedTypeName.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/ByReferenceType.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/ComHelper.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/DefaultSolutionSnapshot.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/DomRegion.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/EntityType.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Error.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/FullTypeName.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/IAmbience.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/IAssembly.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/IAttribute.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/ICodeContext.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/ICompilation.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/IConstantValue.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/IEntity.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/IEvent.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/IField.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/IFreezable.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/IInterningProvider.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/IMember.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/IMethod.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/INamedElement.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/INamespace.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/IParameter.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/IParameterizedMember.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/IProjectContent.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/IProperty.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/ISolutionSnapshot.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/ISupportsInterning.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/ISymbol.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/IType.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/ITypeDefinition.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/ITypeParameter.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/ITypeReference.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/IUnresolvedFile.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/IVariable.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractFreezable.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractResolvedEntity.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractResolvedMember.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractType.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractUnresolvedEntity.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractUnresolvedMember.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/AccessorOwnerMemberReference.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/BaseTypeCollector.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/BlobReader.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultAssemblyReference.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultAttribute.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultMemberReference.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultParameter.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedEvent.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedField.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedMethod.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedProperty.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedTypeParameter.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedAttribute.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedEvent.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedField.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedMethod.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedParameter.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedProperty.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedTypeDefinition.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedTypeParameter.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultVariable.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/DummyTypeParameter.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/ExplicitInterfaceImplementationMemberReference.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/FullNameAndTypeParameterCount.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/GetClassTypeReference.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/GetMembersHelper.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/KnownTypeCache.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/MergedNamespace.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/MinimalCorlib.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/NestedTypeReference.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/ResolvedAttributeBlob.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/SimpleCompilation.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/SimpleConstantValue.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/SimpleInterningProvider.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedEvent.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedField.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMember.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedProperty.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializingMemberReference.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/TypeParameterReference.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/TypeWithElementType.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/UnknownType.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/UnresolvedAttributeBlob.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/UnresolvedSecurityDeclarationBlob.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/VoidTypeDefinition.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/InheritanceHelper.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/IntersectionType.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/KnownTypeReference.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/NullableType.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/ParameterListComparer.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/ParameterizedType.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/PointerType.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/ProjectReference.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/ReflectionHelper.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/ReflectionNameParseException.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/SimpleTypeResolveContext.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/SpecialType.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/TaskType.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/TopLevelTypeName.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/TypeKind.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/TypeParameterSubstitution.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs create mode 100644 ICSharpCode.Decompiler/TypeSystem/TypeVisitor.cs create mode 100644 ICSharpCode.Decompiler/Util/7BitEncodedInts.cs create mode 100644 ICSharpCode.Decompiler/Util/BitVector16.cs create mode 100644 ICSharpCode.Decompiler/Util/BusyManager.cs create mode 100644 ICSharpCode.Decompiler/Util/CSharpPrimitiveCast.cs create mode 100644 ICSharpCode.Decompiler/Util/CacheManager.cs create mode 100644 ICSharpCode.Decompiler/Util/CallbackOnDispose.cs create mode 100644 ICSharpCode.Decompiler/Util/EmptyList.cs create mode 100644 ICSharpCode.Decompiler/Util/ExtensionMethods.cs create mode 100644 ICSharpCode.Decompiler/Util/FastSerializer.cs create mode 100644 ICSharpCode.Decompiler/Util/ImmutableStack.cs create mode 100644 ICSharpCode.Decompiler/Util/LazyInit.cs create mode 100644 ICSharpCode.Decompiler/Util/MultiDictionary.cs create mode 100644 ICSharpCode.Decompiler/Util/Platform.cs create mode 100644 ICSharpCode.Decompiler/Util/ProjectedList.cs create mode 100644 ICSharpCode.Decompiler/Util/ReferenceComparer.cs create mode 100644 ICSharpCode.Decompiler/Util/TreeTraversal.cs diff --git a/ICSharpCode.Decompiler/CSharp/Analysis/ControlFlow.cs b/ICSharpCode.Decompiler/CSharp/Analysis/ControlFlow.cs index 4db0c5bbf..79cde5c06 100644 --- a/ICSharpCode.Decompiler/CSharp/Analysis/ControlFlow.cs +++ b/ICSharpCode.Decompiler/CSharp/Analysis/ControlFlow.cs @@ -734,53 +734,53 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis /// /// Debugging helper that exports a control flow graph. /// - public static GraphVizGraph ExportGraph(IList nodes) - { - GraphVizGraph g = new GraphVizGraph(); - GraphVizNode[] n = new GraphVizNode[nodes.Count]; - Dictionary dict = new Dictionary(); - for (int i = 0; i < n.Length; i++) { - dict.Add(nodes[i], i); - n[i] = new GraphVizNode(i); - string name = "#" + i + " = "; - switch (nodes[i].Type) { - case ControlFlowNodeType.StartNode: - case ControlFlowNodeType.BetweenStatements: - name += nodes[i].NextStatement.DebugToString(); - break; - case ControlFlowNodeType.EndNode: - name += "End of " + nodes[i].PreviousStatement.DebugToString(); - break; - case ControlFlowNodeType.LoopCondition: - name += "Condition in " + nodes[i].NextStatement.DebugToString(); - break; - default: - name += "?"; - break; - } - n[i].label = name; - g.AddNode(n[i]); - } - for (int i = 0; i < n.Length; i++) { - foreach (ControlFlowEdge edge in nodes[i].Outgoing) { - GraphVizEdge ge = new GraphVizEdge(i, dict[edge.To]); - if (edge.IsLeavingTryFinally) - ge.style = "dashed"; - switch (edge.Type) { - case ControlFlowEdgeType.ConditionTrue: - ge.color = "green"; - break; - case ControlFlowEdgeType.ConditionFalse: - ge.color = "red"; - break; - case ControlFlowEdgeType.Jump: - ge.color = "blue"; - break; - } - g.AddEdge(ge); - } - } - return g; - } + //public static GraphVizGraph ExportGraph(IList nodes) + //{ + // GraphVizGraph g = new GraphVizGraph(); + // GraphVizNode[] n = new GraphVizNode[nodes.Count]; + // Dictionary dict = new Dictionary(); + // for (int i = 0; i < n.Length; i++) { + // dict.Add(nodes[i], i); + // n[i] = new GraphVizNode(i); + // string name = "#" + i + " = "; + // switch (nodes[i].Type) { + // case ControlFlowNodeType.StartNode: + // case ControlFlowNodeType.BetweenStatements: + // name += nodes[i].NextStatement.DebugToString(); + // break; + // case ControlFlowNodeType.EndNode: + // name += "End of " + nodes[i].PreviousStatement.DebugToString(); + // break; + // case ControlFlowNodeType.LoopCondition: + // name += "Condition in " + nodes[i].NextStatement.DebugToString(); + // break; + // default: + // name += "?"; + // break; + // } + // n[i].label = name; + // g.AddNode(n[i]); + // } + // for (int i = 0; i < n.Length; i++) { + // foreach (ControlFlowEdge edge in nodes[i].Outgoing) { + // GraphVizEdge ge = new GraphVizEdge(i, dict[edge.To]); + // if (edge.IsLeavingTryFinally) + // ge.style = "dashed"; + // switch (edge.Type) { + // case ControlFlowEdgeType.ConditionTrue: + // ge.color = "green"; + // break; + // case ControlFlowEdgeType.ConditionFalse: + // ge.color = "red"; + // break; + // case ControlFlowEdgeType.Jump: + // ge.color = "blue"; + // break; + // } + // g.AddEdge(ge); + // } + // } + // return g; + //} } } diff --git a/ICSharpCode.Decompiler/CSharp/Analysis/DefiniteAssignmentAnalysis.cs b/ICSharpCode.Decompiler/CSharp/Analysis/DefiniteAssignmentAnalysis.cs index 5c180977d..eef55dd3f 100644 --- a/ICSharpCode.Decompiler/CSharp/Analysis/DefiniteAssignmentAnalysis.cs +++ b/ICSharpCode.Decompiler/CSharp/Analysis/DefiniteAssignmentAnalysis.cs @@ -233,7 +233,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis return conditionNodeDict[statement].NodeStatus; } - /// + /*/// /// Exports the CFG. This method is intended to help debugging issues related to definite assignment. /// public GraphVizGraph ExportGraph() @@ -279,7 +279,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis } } return g; - } + }*/ static DefiniteAssignmentStatus MergeStatus(DefiniteAssignmentStatus a, DefiniteAssignmentStatus b) { diff --git a/ICSharpCode.Decompiler/CSharp/Ast/IAnnotatable.cs b/ICSharpCode.Decompiler/CSharp/Ast/IAnnotatable.cs new file mode 100644 index 000000000..9030de417 --- /dev/null +++ b/ICSharpCode.Decompiler/CSharp/Ast/IAnnotatable.cs @@ -0,0 +1,252 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; +using System.Threading; + +namespace ICSharpCode.NRefactory +{ + /// + /// Provides an interface to handle annotations in an object. + /// + public interface IAnnotatable + { + /// + /// Gets all annotations stored on this IAnnotatable. + /// + IEnumerable Annotations { + get; + } + + /// + /// Gets the first annotation of the specified type. + /// Returns null if no matching annotation exists. + /// + /// + /// The type of the annotation. + /// + T Annotation () where T: class; + + /// + /// Gets the first annotation of the specified type. + /// Returns null if no matching annotation exists. + /// + /// + /// The type of the annotation. + /// + object Annotation (Type type); + + /// + /// Adds an annotation to this instance. + /// + /// + /// The annotation to add. + /// + void AddAnnotation (object annotation); + + /// + /// Removes all annotations of the specified type. + /// + /// + /// The type of the annotations to remove. + /// + void RemoveAnnotations () where T : class; + + /// + /// Removes all annotations of the specified type. + /// + /// + /// The type of the annotations to remove. + /// + void RemoveAnnotations(Type type); + } + + /// + /// Base class used to implement the IAnnotatable interface. + /// This implementation is thread-safe. + /// + [Serializable] + public abstract class AbstractAnnotatable : IAnnotatable + { + // Annotations: points either null (no annotations), to the single annotation, + // or to an AnnotationList. + // Once it is pointed at an AnnotationList, it will never change (this allows thread-safety support by locking the list) + + object annotations; + + /// + /// Clones all annotations. + /// This method is intended to be called by Clone() implementations in derived classes. + /// + /// AstNode copy = (AstNode)MemberwiseClone(); + /// copy.CloneAnnotations(); + /// + /// + protected void CloneAnnotations() + { + ICloneable cloneable = annotations as ICloneable; + if (cloneable != null) + annotations = cloneable.Clone(); + } + + sealed class AnnotationList : List, ICloneable + { + // There are two uses for this custom list type: + // 1) it's private, and thus (unlike List) cannot be confused with real annotations + // 2) It allows us to simplify the cloning logic by making the list behave the same as a clonable annotation. + public AnnotationList (int initialCapacity) : base(initialCapacity) + { + } + + public object Clone () + { + lock (this) { + AnnotationList copy = new AnnotationList (this.Count); + for (int i = 0; i < this.Count; i++) { + object obj = this [i]; + ICloneable c = obj as ICloneable; + copy.Add (c != null ? c.Clone () : obj); + } + return copy; + } + } + } + + public virtual void AddAnnotation (object annotation) + { + if (annotation == null) + throw new ArgumentNullException ("annotation"); + retry: // Retry until successful + object oldAnnotation = Interlocked.CompareExchange (ref this.annotations, annotation, null); + if (oldAnnotation == null) { + return; // we successfully added a single annotation + } + AnnotationList list = oldAnnotation as AnnotationList; + if (list == null) { + // we need to transform the old annotation into a list + list = new AnnotationList (4); + list.Add (oldAnnotation); + list.Add (annotation); + if (Interlocked.CompareExchange (ref this.annotations, list, oldAnnotation) != oldAnnotation) { + // the transformation failed (some other thread wrote to this.annotations first) + goto retry; + } + } else { + // once there's a list, use simple locking + lock (list) { + list.Add (annotation); + } + } + } + + public virtual void RemoveAnnotations () where T : class + { + retry: // Retry until successful + object oldAnnotations = this.annotations; + AnnotationList list = oldAnnotations as AnnotationList; + if (list != null) { + lock (list) + list.RemoveAll (obj => obj is T); + } else if (oldAnnotations is T) { + if (Interlocked.CompareExchange (ref this.annotations, null, oldAnnotations) != oldAnnotations) { + // Operation failed (some other thread wrote to this.annotations first) + goto retry; + } + } + } + + public virtual void RemoveAnnotations (Type type) + { + if (type == null) + throw new ArgumentNullException ("type"); + retry: // Retry until successful + object oldAnnotations = this.annotations; + AnnotationList list = oldAnnotations as AnnotationList; + if (list != null) { + lock (list) + list.RemoveAll(type.IsInstanceOfType); + } else if (type.IsInstanceOfType (oldAnnotations)) { + if (Interlocked.CompareExchange (ref this.annotations, null, oldAnnotations) != oldAnnotations) { + // Operation failed (some other thread wrote to this.annotations first) + goto retry; + } + } + } + + public T Annotation () where T: class + { + object annotations = this.annotations; + AnnotationList list = annotations as AnnotationList; + if (list != null) { + lock (list) { + foreach (object obj in list) { + T t = obj as T; + if (t != null) + return t; + } + return null; + } + } else { + return annotations as T; + } + } + + public object Annotation (Type type) + { + if (type == null) + throw new ArgumentNullException ("type"); + object annotations = this.annotations; + AnnotationList list = annotations as AnnotationList; + if (list != null) { + lock (list) { + foreach (object obj in list) { + if (type.IsInstanceOfType (obj)) + return obj; + } + } + } else { + if (type.IsInstanceOfType (annotations)) + return annotations; + } + return null; + } + + /// + /// Gets all annotations stored on this AstNode. + /// + public IEnumerable Annotations { + get { + object annotations = this.annotations; + AnnotationList list = annotations as AnnotationList; + if (list != null) { + lock (list) { + return list.ToArray (); + } + } else { + if (annotations != null) + return new object[] { annotations }; + else + return Enumerable.Empty (); + } + } + } + } +} + diff --git a/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/AnyNode.cs b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/AnyNode.cs new file mode 100644 index 000000000..f212ba9d4 --- /dev/null +++ b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/AnyNode.cs @@ -0,0 +1,47 @@ +// Copyright (c) 2011-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.PatternMatching +{ + /// + /// Matches any node. + /// + /// Does not match null nodes. + public class AnyNode : Pattern + { + readonly string groupName; + + public string GroupName { + get { return groupName; } + } + + public AnyNode(string groupName = null) + { + this.groupName = groupName; + } + + public override bool DoMatch(INode other, Match match) + { + match.Add(this.groupName, other); + return other != null && !other.IsNull; + } + } + +} diff --git a/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/AnyNodeOrNull.cs b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/AnyNodeOrNull.cs new file mode 100644 index 000000000..092897a4e --- /dev/null +++ b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/AnyNodeOrNull.cs @@ -0,0 +1,58 @@ +// +// AnyNodeOrNull.cs +// +// Author: +// Mike Krüger +// +// Copyright (c) 2013 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; + +namespace ICSharpCode.NRefactory.PatternMatching +{ + /// + /// Matches any node. + /// + /// Does not match null nodes. + public class AnyNodeOrNull : Pattern + { + readonly string groupName; + + public string GroupName { + get { return groupName; } + } + + public AnyNodeOrNull(string groupName = null) + { + this.groupName = groupName; + } + + public override bool DoMatch(INode other, Match match) + { + if (other == null) { + match.AddNull(this.groupName); + } else { + match.Add(this.groupName, other); + } + return true; + } + } +} diff --git a/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Backreference.cs b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Backreference.cs new file mode 100644 index 000000000..eaf17b445 --- /dev/null +++ b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Backreference.cs @@ -0,0 +1,50 @@ +// Copyright (c) 2011-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Linq; + +namespace ICSharpCode.NRefactory.PatternMatching +{ + /// + /// Matches the last entry in the specified named group. + /// + public class Backreference : Pattern + { + readonly string referencedGroupName; + + public string ReferencedGroupName { + get { return referencedGroupName; } + } + + public Backreference(string referencedGroupName) + { + if (referencedGroupName == null) + throw new ArgumentNullException("referencedGroupName"); + this.referencedGroupName = referencedGroupName; + } + + public override bool DoMatch(INode other, Match match) + { + var last = match.Get (referencedGroupName).Last (); + if (last == null && other == null) + return true; + return last.IsMatch(other); + } + } +} diff --git a/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/BacktrackingInfo.cs b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/BacktrackingInfo.cs new file mode 100644 index 000000000..6a0d3ee8e --- /dev/null +++ b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/BacktrackingInfo.cs @@ -0,0 +1,32 @@ +// Copyright (c) 2011-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; + +namespace ICSharpCode.NRefactory.PatternMatching +{ + /// + /// Container for the backtracking info. + /// + public class BacktrackingInfo + { + internal Stack backtrackingStack = new Stack(); + } +} diff --git a/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Choice.cs b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Choice.cs new file mode 100644 index 000000000..ff5e4764e --- /dev/null +++ b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Choice.cs @@ -0,0 +1,68 @@ +// Copyright (c) 2011-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.PatternMatching +{ + /// + /// Matches one of several alternatives. + /// + public class Choice : Pattern, IEnumerable + { + readonly List alternatives = new List(); + + public void Add(string name, INode alternative) + { + if (alternative == null) + throw new ArgumentNullException("alternative"); + alternatives.Add(new NamedNode(name, alternative)); + } + + public void Add(INode alternative) + { + if (alternative == null) + throw new ArgumentNullException("alternative"); + alternatives.Add(alternative); + } + + public override bool DoMatch(INode other, Match match) + { + var checkPoint = match.CheckPoint(); + foreach (INode alt in alternatives) { + if (alt.DoMatch(other, match)) + return true; + else + match.RestoreCheckPoint(checkPoint); + } + return false; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return alternatives.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return alternatives.GetEnumerator(); + } + } +} diff --git a/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/INode.cs b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/INode.cs new file mode 100644 index 000000000..bacf5e461 --- /dev/null +++ b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/INode.cs @@ -0,0 +1,69 @@ +// Copyright (c) 2011-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.PatternMatching +{ + /// + /// AST node that supports pattern matching. + /// + public interface INode + { + Role Role { get; } + INode FirstChild { get; } + INode NextSibling { get; } + bool IsNull { get; } + + bool DoMatch(INode other, Match match); + bool DoMatchCollection(Role role, INode pos, Match match, BacktrackingInfo backtrackingInfo); + } + + public static class PatternExtensions + { + /// + /// Performs a pattern matching operation. + /// this is the pattern, is the AST that is being matched. + /// + /// + /// A match object. Check to see whether the match was successful. + /// + /// + /// Patterns are ASTs that contain special pattern nodes (from the PatternMatching namespace). + /// However, it is also possible to match two ASTs without any pattern nodes - + /// doing so will produce a successful match if the two ASTs are structurally identical. + /// + public static Match Match(this INode pattern, INode other) + { + if (pattern == null) + throw new ArgumentNullException("pattern"); + Match match = PatternMatching.Match.CreateNew(); + if (pattern.DoMatch(other, match)) + return match; + else + return default(PatternMatching.Match); + } + + public static bool IsMatch(this INode pattern, INode other) + { + if (pattern == null) + throw new ArgumentNullException("pattern"); + return pattern.DoMatch(other, PatternMatching.Match.CreateNew()); + } + } +} diff --git a/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Match.cs b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Match.cs new file mode 100644 index 000000000..1a9a9f666 --- /dev/null +++ b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Match.cs @@ -0,0 +1,100 @@ +// Copyright (c) 2011-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; + +namespace ICSharpCode.NRefactory.PatternMatching +{ + /// + /// Represents the result of a pattern matching operation. + /// + public struct Match + { + // TODO: maybe we should add an implicit Match->bool conversion? (implicit operator bool(Match m) { return m != null; }) + + List> results; + + public bool Success { + get { return results != null; } + } + + internal static Match CreateNew() + { + Match m; + m.results = new List>(); + return m; + } + + internal int CheckPoint() + { + return results.Count; + } + + internal void RestoreCheckPoint(int checkPoint) + { + results.RemoveRange(checkPoint, results.Count - checkPoint); + } + + public IEnumerable Get(string groupName) + { + if (results == null) + yield break; + foreach (var pair in results) { + if (pair.Key == groupName) + yield return pair.Value; + } + } + + public IEnumerable Get(string groupName) where T : INode + { + if (results == null) + yield break; + foreach (var pair in results) { + if (pair.Key == groupName) + yield return (T)pair.Value; + } + } + + public bool Has(string groupName) + { + if (results == null) + return false; + foreach (var pair in results) { + if (pair.Key == groupName) + return true; + } + return false; + } + + public void Add(string groupName, INode node) + { + if (groupName != null && node != null) { + results.Add(new KeyValuePair(groupName, node)); + } + } + + internal void AddNull (string groupName) + { + if (groupName != null) { + results.Add(new KeyValuePair(groupName, null)); + } + } + } +} diff --git a/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/NamedNode.cs b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/NamedNode.cs new file mode 100644 index 000000000..464c9a6f4 --- /dev/null +++ b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/NamedNode.cs @@ -0,0 +1,53 @@ +// Copyright (c) 2011-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.PatternMatching +{ + /// + /// Represents a named node within a pattern. + /// + public class NamedNode : Pattern + { + readonly string groupName; + readonly INode childNode; + + public string GroupName { + get { return groupName; } + } + + public INode ChildNode { + get { return childNode; } + } + + public NamedNode(string groupName, INode childNode) + { + if (childNode == null) + throw new ArgumentNullException("childNode"); + this.groupName = groupName; + this.childNode = childNode; + } + + public override bool DoMatch(INode other, Match match) + { + match.Add(this.groupName, other); + return childNode.DoMatch(other, match); + } + } +} diff --git a/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/OptionalNode.cs b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/OptionalNode.cs new file mode 100644 index 000000000..2d72677a1 --- /dev/null +++ b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/OptionalNode.cs @@ -0,0 +1,58 @@ +// Copyright (c) 2011-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Diagnostics; + +namespace ICSharpCode.NRefactory.PatternMatching +{ + public class OptionalNode : Pattern + { + readonly INode childNode; + + public INode ChildNode { + get { return childNode; } + } + + public OptionalNode(INode childNode) + { + if (childNode == null) + throw new ArgumentNullException("childNode"); + this.childNode = childNode; + } + + public OptionalNode(string groupName, INode childNode) : this(new NamedNode(groupName, childNode)) + { + } + + public override bool DoMatchCollection(Role role, INode pos, Match match, BacktrackingInfo backtrackingInfo) + { + backtrackingInfo.backtrackingStack.Push(new PossibleMatch(pos, match.CheckPoint())); + return childNode.DoMatch(pos, match); + } + + public override bool DoMatch(INode other, Match match) + { + if (other == null || other.IsNull) + return true; + else + return childNode.DoMatch(other, match); + } + } +} diff --git a/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Pattern.cs b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Pattern.cs new file mode 100644 index 000000000..c27c9d445 --- /dev/null +++ b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Pattern.cs @@ -0,0 +1,114 @@ +// Copyright (c) 2011-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Diagnostics; +using System.IO; + +namespace ICSharpCode.NRefactory.PatternMatching +{ + /// + /// Base class for all patterns. + /// + public abstract class Pattern : INode + { + /// + /// Gets the string that matches any string. + /// + public static readonly string AnyString = "$any$"; + + public static bool MatchString(string pattern, string text) + { + return pattern == AnyString || pattern == text; + } + + internal struct PossibleMatch + { + public readonly INode NextOther; // next node after the last matched node + public readonly int Checkpoint; // checkpoint + + public PossibleMatch(INode nextOther, int checkpoint) + { + this.NextOther = nextOther; + this.Checkpoint = checkpoint; + } + } + + bool INode.IsNull { + get { return false; } + } + + Role INode.Role { + get { return null; } + } + + INode INode.NextSibling { + get { return null; } + } + + INode INode.FirstChild { + get { return null; } + } + + public abstract bool DoMatch(INode other, Match match); + + public virtual bool DoMatchCollection(Role role, INode pos, Match match, BacktrackingInfo backtrackingInfo) + { + return DoMatch (pos, match); + } + + public static bool DoMatchCollection(Role role, INode firstPatternChild, INode firstOtherChild, Match match) + { + BacktrackingInfo backtrackingInfo = new BacktrackingInfo(); + Stack patternStack = new Stack(); + Stack stack = backtrackingInfo.backtrackingStack; + patternStack.Push(firstPatternChild); + stack.Push(new PossibleMatch(firstOtherChild, match.CheckPoint())); + while (stack.Count > 0) { + INode cur1 = patternStack.Pop(); + INode cur2 = stack.Peek().NextOther; + match.RestoreCheckPoint(stack.Pop().Checkpoint); + bool success = true; + while (cur1 != null && success) { + while (cur1 != null && cur1.Role != role) + cur1 = cur1.NextSibling; + while (cur2 != null && cur2.Role != role) + cur2 = cur2.NextSibling; + if (cur1 == null) + break; + + Debug.Assert(stack.Count == patternStack.Count); + success = cur1.DoMatchCollection(role, cur2, match, backtrackingInfo); + Debug.Assert(stack.Count >= patternStack.Count); + while (stack.Count > patternStack.Count) + patternStack.Push(cur1.NextSibling); + + cur1 = cur1.NextSibling; + if (cur2 != null) + cur2 = cur2.NextSibling; + } + while (cur2 != null && cur2.Role != role) + cur2 = cur2.NextSibling; + if (success && cur2 == null) + return true; + } + return false; + } + } +} diff --git a/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Repeat.cs b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Repeat.cs new file mode 100644 index 000000000..c2b40c5c5 --- /dev/null +++ b/ICSharpCode.Decompiler/CSharp/Ast/PatternMatching/Repeat.cs @@ -0,0 +1,74 @@ +// Copyright (c) 2011-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Diagnostics; + +namespace ICSharpCode.NRefactory.PatternMatching +{ + /// + /// Represents an optional node. + /// + public class Repeat : Pattern + { + readonly INode childNode; + + public int MinCount { get; set; } + public int MaxCount { get; set; } + + public INode ChildNode { + get { return childNode; } + } + + public Repeat(INode childNode) + { + if (childNode == null) + throw new ArgumentNullException("childNode"); + this.childNode = childNode; + this.MinCount = 0; + this.MaxCount = int.MaxValue; + } + + public override bool DoMatchCollection(Role role, INode pos, Match match, BacktrackingInfo backtrackingInfo) + { + var backtrackingStack = backtrackingInfo.backtrackingStack; + Debug.Assert(pos == null || pos.Role == role); + int matchCount = 0; + if (this.MinCount <= 0) + backtrackingStack.Push(new PossibleMatch(pos, match.CheckPoint())); + while (matchCount < this.MaxCount && pos != null && childNode.DoMatch(pos, match)) { + matchCount++; + do { + pos = pos.NextSibling; + } while (pos != null && pos.Role != role); + if (matchCount >= this.MinCount) + backtrackingStack.Push(new PossibleMatch(pos, match.CheckPoint())); + } + return false; // never do a normal (single-element) match; always make the caller look at the results on the back-tracking stack. + } + + public override bool DoMatch(INode other, Match match) + { + if (other == null || other.IsNull) + return this.MinCount <= 0; + else + return this.MaxCount >= 1 && childNode.DoMatch(other, match); + } + } +} diff --git a/ICSharpCode.Decompiler/CSharp/Ast/Role.cs b/ICSharpCode.Decompiler/CSharp/Ast/Role.cs new file mode 100644 index 000000000..2a84b464e --- /dev/null +++ b/ICSharpCode.Decompiler/CSharp/Ast/Role.cs @@ -0,0 +1,113 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Threading; + +namespace ICSharpCode.NRefactory +{ + /// + /// Represents the role a node plays within its parent. + /// + public abstract class Role + { + public const int RoleIndexBits = 9; + + static readonly Role[] roles = new Role[1 << RoleIndexBits]; + static int nextRoleIndex = 0; + + readonly uint index; + + [CLSCompliant(false)] + public uint Index { + get { return index; } + } + + // don't allow NRefactory consumers to derive from Role + internal Role() + { + this.index = (uint)Interlocked.Increment(ref nextRoleIndex); + if (this.index >= roles.Length) + throw new InvalidOperationException("Too many roles"); + roles[this.index] = this; + } + + /// + /// Gets whether the specified node is valid in this role. + /// + public abstract bool IsValid(object node); + + /// + /// Gets the role with the specified index. + /// + [CLSCompliant(false)] + public static Role GetByIndex(uint index) + { + return roles[index]; + } + } + + /// + /// Represents the role a node plays within its parent. + /// All nodes with this role have type T. + /// + public class Role : Role where T : class + { + readonly string name; // helps with debugging the AST + readonly T nullObject; + + /// + /// Gets the null object used when there's no node with this role. + /// Not every role has a null object; this property returns null for roles without a null object. + /// + /// + /// Roles used for non-collections should always have a null object, so that no AST property returns null. + /// However, if a role used for collections only, it may leave out the null object. + /// + public T NullObject { + get { return nullObject; } + } + + public override bool IsValid(object node) + { + return node is T; + } + + public Role(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + this.name = name; + } + + public Role(string name, T nullObject) + { + if (name == null) + throw new ArgumentNullException("name"); + if (nullObject == null) + throw new ArgumentNullException ("nullObject"); + this.nullObject = nullObject; + this.name = name; + } + + public override string ToString() + { + return name; + } + } +} diff --git a/ICSharpCode.Decompiler/CSharp/Ast/TextLocation.cs b/ICSharpCode.Decompiler/CSharp/Ast/TextLocation.cs new file mode 100644 index 000000000..ead697ce8 --- /dev/null +++ b/ICSharpCode.Decompiler/CSharp/Ast/TextLocation.cs @@ -0,0 +1,223 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.ComponentModel; +using System.Globalization; + +namespace ICSharpCode.NRefactory +{ + /// + /// A line/column position. + /// Text editor lines/columns are counted started from one. + /// + /// + /// The document provides the methods and + /// to convert between offsets and TextLocations. + /// + [Serializable] + [TypeConverter(typeof(TextLocationConverter))] + public struct TextLocation : IComparable, IEquatable + { + /// + /// Represents no text location (0, 0). + /// + public static readonly TextLocation Empty = new TextLocation(0, 0); + + /// + /// Constant of the minimum line. + /// + public const int MinLine = 1; + + /// + /// Constant of the minimum column. + /// + public const int MinColumn = 1; + + /// + /// Creates a TextLocation instance. + /// + public TextLocation(int line, int column) + { + this.line = line; + this.column = column; + } + + int column, line; + + /// + /// Gets the line number. + /// + public int Line { + get { return line; } + } + + /// + /// Gets the column number. + /// + public int Column { + get { return column; } + } + + /// + /// Gets whether the TextLocation instance is empty. + /// + public bool IsEmpty { + get { + return column < MinLine && line < MinColumn; + } + } + + /// + /// Gets a string representation for debugging purposes. + /// + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "(Line {1}, Col {0})", this.column, this.line); + } + + /// + /// Gets a hash code. + /// + public override int GetHashCode() + { + return unchecked (191 * column.GetHashCode() ^ line.GetHashCode()); + } + + /// + /// Equality test. + /// + public override bool Equals(object obj) + { + if (!(obj is TextLocation)) return false; + return (TextLocation)obj == this; + } + + /// + /// Equality test. + /// + public bool Equals(TextLocation other) + { + return this == other; + } + + /// + /// Equality test. + /// + public static bool operator ==(TextLocation left, TextLocation right) + { + return left.column == right.column && left.line == right.line; + } + + /// + /// Inequality test. + /// + public static bool operator !=(TextLocation left, TextLocation right) + { + return left.column != right.column || left.line != right.line; + } + + /// + /// Compares two text locations. + /// + public static bool operator <(TextLocation left, TextLocation right) + { + if (left.line < right.line) + return true; + else if (left.line == right.line) + return left.column < right.column; + else + return false; + } + + /// + /// Compares two text locations. + /// + public static bool operator >(TextLocation left, TextLocation right) + { + if (left.line > right.line) + return true; + else if (left.line == right.line) + return left.column > right.column; + else + return false; + } + + /// + /// Compares two text locations. + /// + public static bool operator <=(TextLocation left, TextLocation right) + { + return !(left > right); + } + + /// + /// Compares two text locations. + /// + public static bool operator >=(TextLocation left, TextLocation right) + { + return !(left < right); + } + + /// + /// Compares two text locations. + /// + public int CompareTo(TextLocation other) + { + if (this == other) + return 0; + if (this < other) + return -1; + else + return 1; + } + } + + public class TextLocationConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + return destinationType == typeof(TextLocation) || base.CanConvertTo(context, destinationType); + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value is string) { + string[] parts = ((string)value).Split(';', ','); + if (parts.Length == 2) { + return new TextLocation(int.Parse(parts[0]), int.Parse(parts[1])); + } + } + return base.ConvertFrom(context, culture, value); + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (value is TextLocation) { + var loc = (TextLocation)value; + return loc.Line + ";" + loc.Column; + } + return base.ConvertTo(context, culture, value, destinationType); + } + } +} diff --git a/ICSharpCode.Decompiler/Documentation/DocumentationComment.cs b/ICSharpCode.Decompiler/Documentation/DocumentationComment.cs new file mode 100644 index 000000000..a93758bd7 --- /dev/null +++ b/ICSharpCode.Decompiler/Documentation/DocumentationComment.cs @@ -0,0 +1,95 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.Editor; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Documentation +{ + /// + /// Represents a documentation comment. + /// + public class DocumentationComment + { + ITextSource xml; + protected readonly ITypeResolveContext context; + + /// + /// Gets the XML code for this documentation comment. + /// + public ITextSource Xml { + get { return xml; } + } + + /// + /// Creates a new DocumentationComment. + /// + /// The XML text. + /// Context for resolving cref attributes. + public DocumentationComment(ITextSource xml, ITypeResolveContext context) + { + if (xml == null) + throw new ArgumentNullException("xml"); + if (context == null) + throw new ArgumentNullException("context"); + this.xml = xml; + this.context = context; + } + + /// + /// Creates a new DocumentationComment. + /// + /// The XML text. + /// Context for resolving cref attributes. + public DocumentationComment(string xml, ITypeResolveContext context) + { + if (xml == null) + throw new ArgumentNullException("xml"); + if (context == null) + throw new ArgumentNullException("context"); + this.xml = new StringTextSource(xml); + this.context = context; + } + + /// + /// Resolves the given cref value to an entity. + /// Returns null if the entity is not found, or if the cref attribute is syntactically invalid. + /// + public virtual IEntity ResolveCref(string cref) + { + try { + return IdStringProvider.FindEntity(cref, context); + } catch (ReflectionNameParseException) { + return null; + } + } + + public override string ToString () + { + return Xml.Text; + } + + public static implicit operator string (DocumentationComment documentationComment) + { + if (documentationComment != null) + return documentationComment.ToString (); + return null; + } + } +} diff --git a/ICSharpCode.Decompiler/Documentation/GetPotentiallyNestedClassTypeReference.cs b/ICSharpCode.Decompiler/Documentation/GetPotentiallyNestedClassTypeReference.cs new file mode 100644 index 000000000..1e5807d77 --- /dev/null +++ b/ICSharpCode.Decompiler/Documentation/GetPotentiallyNestedClassTypeReference.cs @@ -0,0 +1,71 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Linq; +using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.TypeSystem.Implementation; + +namespace ICSharpCode.NRefactory.Documentation +{ + /// + /// A type reference of the form 'Some.Namespace.TopLevelType.NestedType`n'. + /// We do not know the boundary between namespace name and top level type, so we have to try + /// all possibilities. + /// The type parameter count only applies to the innermost type, all outer types must be non-generic. + /// + [Serializable] + class GetPotentiallyNestedClassTypeReference : ITypeReference + { + readonly string typeName; + readonly int typeParameterCount; + + public GetPotentiallyNestedClassTypeReference(string typeName, int typeParameterCount) + { + this.typeName = typeName; + this.typeParameterCount = typeParameterCount; + } + + public IType Resolve(ITypeResolveContext context) + { + string[] parts = typeName.Split('.'); + var assemblies = new [] { context.CurrentAssembly }.Concat(context.Compilation.Assemblies); + for (int i = parts.Length - 1; i >= 0; i--) { + string ns = string.Join(".", parts, 0, i); + string name = parts[i]; + int topLevelTPC = (i == parts.Length - 1 ? typeParameterCount : 0); + foreach (var asm in assemblies) { + if (asm == null) + continue; + ITypeDefinition typeDef = asm.GetTypeDefinition(new TopLevelTypeName(ns, name, topLevelTPC)); + for (int j = i + 1; j < parts.Length && typeDef != null; j++) { + int tpc = (j == parts.Length - 1 ? typeParameterCount : 0); + typeDef = typeDef.NestedTypes.FirstOrDefault(n => n.Name == parts[j] && n.TypeParameterCount == tpc); + } + if (typeDef != null) + return typeDef; + } + } + int idx = typeName.LastIndexOf('.'); + if (idx < 0) + return new UnknownType("", typeName, typeParameterCount); + // give back a guessed namespace/type name + return new UnknownType(typeName.Substring(0, idx), typeName.Substring(idx + 1), typeParameterCount); + } + } +} diff --git a/ICSharpCode.Decompiler/Documentation/IDocumentationProvider.cs b/ICSharpCode.Decompiler/Documentation/IDocumentationProvider.cs new file mode 100644 index 000000000..d02dea360 --- /dev/null +++ b/ICSharpCode.Decompiler/Documentation/IDocumentationProvider.cs @@ -0,0 +1,51 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.IO; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Documentation +{ + /// + /// Provides XML documentation for entities. + /// + public interface IDocumentationProvider + { + /// + /// Gets the XML documentation for the specified entity. + /// + DocumentationComment GetDocumentation(IEntity entity); + } + + /// + /// Provides XML documentation for entities. + /// + public interface IUnresolvedDocumentationProvider + { + /// + /// Gets the XML documentation for the specified entity. + /// + string GetDocumentation(IUnresolvedEntity entity); + + /// + /// Gets the XML documentation for the specified entity. + /// + DocumentationComment GetDocumentation(IUnresolvedEntity entity, IEntity resolvedEntity); + } +} diff --git a/ICSharpCode.Decompiler/Documentation/IdStringMemberReference.cs b/ICSharpCode.Decompiler/Documentation/IdStringMemberReference.cs new file mode 100644 index 000000000..db7706e02 --- /dev/null +++ b/ICSharpCode.Decompiler/Documentation/IdStringMemberReference.cs @@ -0,0 +1,77 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Documentation +{ + [Serializable] + class IdStringMemberReference : IMemberReference + { + readonly ITypeReference declaringTypeReference; + readonly char memberType; + readonly string memberIdString; + + public IdStringMemberReference(ITypeReference declaringTypeReference, char memberType, string memberIdString) + { + this.declaringTypeReference = declaringTypeReference; + this.memberType = memberType; + this.memberIdString = memberIdString; + } + + bool CanMatch(IUnresolvedMember member) + { + switch (member.SymbolKind) { + case SymbolKind.Field: + return memberType == 'F'; + case SymbolKind.Property: + case SymbolKind.Indexer: + return memberType == 'P'; + case SymbolKind.Event: + return memberType == 'E'; + case SymbolKind.Method: + case SymbolKind.Operator: + case SymbolKind.Constructor: + case SymbolKind.Destructor: + return memberType == 'M'; + default: + throw new NotSupportedException(member.SymbolKind.ToString()); + } + } + + public ITypeReference DeclaringTypeReference { + get { return declaringTypeReference; } + } + + public IMember Resolve(ITypeResolveContext context) + { + IType declaringType = declaringTypeReference.Resolve(context); + foreach (var member in declaringType.GetMembers(CanMatch, GetMemberOptions.IgnoreInheritedMembers)) { + if (IdStringProvider.GetIdString(member) == memberIdString) + return member; + } + return null; + } + + ISymbol ISymbolReference.Resolve(ITypeResolveContext context) + { + return Resolve(context); + } + } +} diff --git a/ICSharpCode.Decompiler/Documentation/IdStringProvider.cs b/ICSharpCode.Decompiler/Documentation/IdStringProvider.cs new file mode 100644 index 000000000..3b2315628 --- /dev/null +++ b/ICSharpCode.Decompiler/Documentation/IdStringProvider.cs @@ -0,0 +1,393 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Linq; +using System.Collections.Generic; +using System.Text; +using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.TypeSystem.Implementation; + +namespace ICSharpCode.NRefactory.Documentation +{ + /// + /// Provides ID strings for entities. (C# 4.0 spec, §A.3.1) + /// ID strings are used to identify members in XML documentation files. + /// + public static class IdStringProvider + { + #region GetIdString + /// + /// Gets the ID string (C# 4.0 spec, §A.3.1) for the specified entity. + /// + public static string GetIdString(this IEntity entity) + { + StringBuilder b = new StringBuilder(); + switch (entity.SymbolKind) { + case SymbolKind.TypeDefinition: + b.Append("T:"); + AppendTypeName(b, (ITypeDefinition)entity, false); + return b.ToString(); + case SymbolKind.Field: + b.Append("F:"); + break; + case SymbolKind.Property: + case SymbolKind.Indexer: + b.Append("P:"); + break; + case SymbolKind.Event: + b.Append("E:"); + break; + default: + b.Append("M:"); + break; + } + IMember member = (IMember)entity; + if (member.DeclaringType != null) { + AppendTypeName(b, member.DeclaringType, false); + b.Append('.'); + } + if (member.IsExplicitInterfaceImplementation && member.Name.IndexOf('.') < 0 && member.ImplementedInterfaceMembers.Count == 1) { + AppendTypeName(b, member.ImplementedInterfaceMembers[0].DeclaringType, true); + b.Append('#'); + } + b.Append(member.Name.Replace('.', '#')); + IMethod method = member as IMethod; + if (method != null && method.TypeParameters.Count > 0) { + b.Append("``"); + b.Append(method.TypeParameters.Count); + } + IParameterizedMember parameterizedMember = member as IParameterizedMember; + if (parameterizedMember != null && parameterizedMember.Parameters.Count > 0) { + b.Append('('); + var parameters = parameterizedMember.Parameters; + for (int i = 0; i < parameters.Count; i++) { + if (i > 0) b.Append(','); + AppendTypeName(b, parameters[i].Type, false); + } + b.Append(')'); + } + if (member.SymbolKind == SymbolKind.Operator && (member.Name == "op_Implicit" || member.Name == "op_Explicit")) { + b.Append('~'); + AppendTypeName(b, member.ReturnType, false); + } + return b.ToString(); + } + #endregion + + #region GetTypeName + public static string GetTypeName(IType type) + { + if (type == null) + throw new ArgumentNullException("type"); + StringBuilder b = new StringBuilder(); + AppendTypeName(b, type, false); + return b.ToString(); + } + + static void AppendTypeName(StringBuilder b, IType type, bool explicitInterfaceImpl) + { + switch (type.Kind) { + case TypeKind.Dynamic: + b.Append(explicitInterfaceImpl ? "System#Object" : "System.Object"); + break; + case TypeKind.TypeParameter: + ITypeParameter tp = (ITypeParameter)type; + if (explicitInterfaceImpl) { + b.Append(tp.Name); + } else { + b.Append('`'); + if (tp.OwnerType == SymbolKind.Method) + b.Append('`'); + b.Append(tp.Index); + } + break; + case TypeKind.Array: + ArrayType array = (ArrayType)type; + AppendTypeName(b, array.ElementType, explicitInterfaceImpl); + b.Append('['); + if (array.Dimensions > 1) { + for (int i = 0; i < array.Dimensions; i++) { + if (i > 0) + b.Append(explicitInterfaceImpl ? '@' : ','); + if (!explicitInterfaceImpl) + b.Append("0:"); + } + } + b.Append(']'); + break; + case TypeKind.Pointer: + AppendTypeName(b, ((PointerType)type).ElementType, explicitInterfaceImpl); + b.Append('*'); + break; + case TypeKind.ByReference: + AppendTypeName(b, ((ByReferenceType)type).ElementType, explicitInterfaceImpl); + b.Append('@'); + break; + default: + IType declType = type.DeclaringType; + if (declType != null) { + AppendTypeName(b, declType, explicitInterfaceImpl); + b.Append(explicitInterfaceImpl ? '#' : '.'); + b.Append(type.Name); + AppendTypeParameters(b, type, declType.TypeParameterCount, explicitInterfaceImpl); + } else { + if (explicitInterfaceImpl) + b.Append(type.FullName.Replace('.', '#')); + else + b.Append(type.FullName); + AppendTypeParameters(b, type, 0, explicitInterfaceImpl); + } + break; + } + } + + static void AppendTypeParameters(StringBuilder b, IType type, int outerTypeParameterCount, bool explicitInterfaceImpl) + { + int tpc = type.TypeParameterCount - outerTypeParameterCount; + if (tpc > 0) { + ParameterizedType pt = type as ParameterizedType; + if (pt != null) { + b.Append('{'); + var ta = pt.TypeArguments; + for (int i = outerTypeParameterCount; i < ta.Count; i++) { + if (i > outerTypeParameterCount) + b.Append(explicitInterfaceImpl ? '@' : ','); + AppendTypeName(b, ta[i], explicitInterfaceImpl); + } + b.Append('}'); + } else { + b.Append('`'); + b.Append(tpc); + } + } + } + #endregion + + #region ParseMemberName + /// + /// Parse the ID string into a member reference. + /// + /// The ID string representing the member (with "M:", "F:", "P:" or "E:" prefix). + /// A member reference that represents the ID string. + /// The syntax of the ID string is invalid + /// + /// The member reference will look in first, + /// and if the member is not found there, + /// it will look in all other assemblies of the compilation. + /// + public static IMemberReference ParseMemberIdString(string memberIdString) + { + if (memberIdString == null) + throw new ArgumentNullException("memberIdString"); + if (memberIdString.Length < 2 || memberIdString[1] != ':') + throw new ReflectionNameParseException(0, "Missing type tag"); + char typeChar = memberIdString[0]; + int parenPos = memberIdString.IndexOf('('); + if (parenPos < 0) + parenPos = memberIdString.LastIndexOf('~'); + if (parenPos < 0) + parenPos = memberIdString.Length; + int dotPos = memberIdString.LastIndexOf('.', parenPos - 1); + if (dotPos < 0) + throw new ReflectionNameParseException(0, "Could not find '.' separating type name from member name"); + string typeName = memberIdString.Substring(0, dotPos); + int pos = 2; + ITypeReference typeReference = ParseTypeName(typeName, ref pos); + if (pos != typeName.Length) + throw new ReflectionNameParseException(pos, "Expected end of type name"); +// string memberName = memberIDString.Substring(dotPos + 1, parenPos - (dotPos + 1)); +// pos = memberName.LastIndexOf("``"); +// if (pos > 0) +// memberName = memberName.Substring(0, pos); +// memberName = memberName.Replace('#', '.'); + return new IdStringMemberReference(typeReference, typeChar, memberIdString); + } + #endregion + + #region ParseTypeName + /// + /// Parse the ID string type name into a type reference. + /// + /// The ID string representing the type (the "T:" prefix is optional). + /// A type reference that represents the ID string. + /// The syntax of the ID string is invalid + /// + /// + /// The type reference will look in first, + /// and if the type is not found there, + /// it will look in all other assemblies of the compilation. + /// + /// + /// If the type is open (contains type parameters '`0' or '``0'), + /// an with the appropriate CurrentTypeDefinition/CurrentMember is required + /// to resolve the reference to the ITypeParameter. + /// + /// + public static ITypeReference ParseTypeName(string typeName) + { + if (typeName == null) + throw new ArgumentNullException("typeName"); + int pos = 0; + if (typeName.StartsWith("T:", StringComparison.Ordinal)) + pos = 2; + ITypeReference r = ParseTypeName(typeName, ref pos); + if (pos < typeName.Length) + throw new ReflectionNameParseException(pos, "Expected end of type name"); + return r; + } + + static bool IsIDStringSpecialCharacter(char c) + { + switch (c) { + case ':': + case '{': + case '}': + case '[': + case ']': + case '(': + case ')': + case '`': + case '*': + case '@': + case ',': + return true; + default: + return false; + } + } + + static ITypeReference ParseTypeName(string typeName, ref int pos) + { + string reflectionTypeName = typeName; + if (pos == typeName.Length) + throw new ReflectionNameParseException(pos, "Unexpected end"); + ITypeReference result; + if (reflectionTypeName[pos] == '`') { + // type parameter reference + pos++; + if (pos == reflectionTypeName.Length) + throw new ReflectionNameParseException(pos, "Unexpected end"); + if (reflectionTypeName[pos] == '`') { + // method type parameter reference + pos++; + int index = ReflectionHelper.ReadTypeParameterCount(reflectionTypeName, ref pos); + result = TypeParameterReference.Create(SymbolKind.Method, index); + } else { + // class type parameter reference + int index = ReflectionHelper.ReadTypeParameterCount(reflectionTypeName, ref pos); + result = TypeParameterReference.Create(SymbolKind.TypeDefinition, index); + } + } else { + // not a type parameter reference: read the actual type name + List typeArguments = new List(); + int typeParameterCount; + string typeNameWithoutSuffix = ReadTypeName(typeName, ref pos, true, out typeParameterCount, typeArguments); + result = new GetPotentiallyNestedClassTypeReference(typeNameWithoutSuffix, typeParameterCount); + while (pos < typeName.Length && typeName[pos] == '.') { + pos++; + string nestedTypeName = ReadTypeName(typeName, ref pos, false, out typeParameterCount, typeArguments); + result = new NestedTypeReference(result, nestedTypeName, typeParameterCount); + } + if (typeArguments.Count > 0) { + result = new ParameterizedTypeReference(result, typeArguments); + } + } + while (pos < typeName.Length) { + switch (typeName[pos]) { + case '[': + int dimensions = 1; + do { + pos++; + if (pos == typeName.Length) + throw new ReflectionNameParseException(pos, "Unexpected end"); + if (typeName[pos] == ',') + dimensions++; + } while (typeName[pos] != ']'); + result = new ArrayTypeReference(result, dimensions); + break; + case '*': + result = new PointerTypeReference(result); + break; + case '@': + result = new ByReferenceTypeReference(result); + break; + default: + return result; + } + pos++; + } + return result; + } + + static string ReadTypeName(string typeName, ref int pos, bool allowDottedName, out int typeParameterCount, List typeArguments) + { + int startPos = pos; + // skip the simple name portion: + while (pos < typeName.Length && !IsIDStringSpecialCharacter(typeName[pos]) && (allowDottedName || typeName[pos] != '.')) + pos++; + if (pos == startPos) + throw new ReflectionNameParseException(pos, "Expected type name"); + string shortTypeName = typeName.Substring(startPos, pos - startPos); + // read type arguments: + typeParameterCount = 0; + if (pos < typeName.Length && typeName[pos] == '`') { + // unbound generic type + pos++; + typeParameterCount = ReflectionHelper.ReadTypeParameterCount(typeName, ref pos); + } else if (pos < typeName.Length && typeName[pos] == '{') { + // bound generic type + typeArguments = new List(); + do { + pos++; + typeArguments.Add(ParseTypeName(typeName, ref pos)); + typeParameterCount++; + if (pos == typeName.Length) + throw new ReflectionNameParseException(pos, "Unexpected end"); + } while (typeName[pos] == ','); + if (typeName[pos] != '}') + throw new ReflectionNameParseException(pos, "Expected '}'"); + pos++; + } + return shortTypeName; + } + #endregion + + #region FindEntity + /// + /// Finds the entity in the given type resolve context. + /// + /// ID string of the entity. + /// Type resolve context + /// Returns the entity, or null if it is not found. + /// The syntax of the ID string is invalid + public static IEntity FindEntity(string idString, ITypeResolveContext context) + { + if (idString == null) + throw new ArgumentNullException("idString"); + if (context == null) + throw new ArgumentNullException("context"); + if (idString.StartsWith("T:", StringComparison.Ordinal)) { + return ParseTypeName(idString.Substring(2)).Resolve(context).GetDefinition(); + } else { + return ParseMemberIdString(idString).Resolve(context); + } + } + #endregion + } +} diff --git a/ICSharpCode.Decompiler/Documentation/XmlDocumentationProvider.cs b/ICSharpCode.Decompiler/Documentation/XmlDocumentationProvider.cs new file mode 100644 index 000000000..ae9a0a1fa --- /dev/null +++ b/ICSharpCode.Decompiler/Documentation/XmlDocumentationProvider.cs @@ -0,0 +1,422 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Diagnostics; +using System.IO; +using System.Runtime.Serialization; +using System.Text; +using System.Xml; +using ICSharpCode.NRefactory.Editor; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Documentation +{ + /// + /// Provides documentation from an .xml file (as generated by the Microsoft C# compiler). + /// + /// + /// This class first creates an in-memory index of the .xml file, and then uses that to read only the requested members. + /// This way, we avoid keeping all the documentation in memory. + /// The .xml file is only opened when necessary, the file handle is not kept open all the time. + /// If the .xml file is changed, the index will automatically be recreated. + /// + [Serializable] + public class XmlDocumentationProvider : IDocumentationProvider, IDeserializationCallback + { + #region Cache + sealed class XmlDocumentationCache + { + readonly KeyValuePair[] entries; + int pos; + + public XmlDocumentationCache(int size = 50) + { + if (size <= 0) + throw new ArgumentOutOfRangeException("size", size, "Value must be positive"); + this.entries = new KeyValuePair[size]; + } + + internal bool TryGet(string key, out string value) + { + foreach (var pair in entries) { + if (pair.Key == key) { + value = pair.Value; + return true; + } + } + value = null; + return false; + } + + internal void Add(string key, string value) + { + entries[pos++] = new KeyValuePair(key, value); + if (pos == entries.Length) + pos = 0; + } + } + #endregion + + [Serializable] + struct IndexEntry : IComparable + { + /// + /// Hash code of the documentation tag + /// + internal readonly int HashCode; + + /// + /// Position in the .xml file where the documentation starts + /// + internal readonly int PositionInFile; + + internal IndexEntry(int hashCode, int positionInFile) + { + this.HashCode = hashCode; + this.PositionInFile = positionInFile; + } + + public int CompareTo(IndexEntry other) + { + return this.HashCode.CompareTo(other.HashCode); + } + } + + [NonSerialized] + XmlDocumentationCache cache = new XmlDocumentationCache(); + + readonly string fileName; + readonly Encoding encoding; + volatile IndexEntry[] index; // SORTED array of index entries + + #region Constructor / Redirection support + /// + /// Creates a new XmlDocumentationProvider. + /// + /// Name of the .xml file. + /// Error reading from XML file (or from redirected file) + /// Invalid XML file + public XmlDocumentationProvider(string fileName) + { + if (fileName == null) + throw new ArgumentNullException("fileName"); + + using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete)) { + using (XmlTextReader xmlReader = new XmlTextReader(fs)) { + xmlReader.XmlResolver = null; // no DTD resolving + xmlReader.MoveToContent(); + if (string.IsNullOrEmpty(xmlReader.GetAttribute("redirect"))) { + this.fileName = fileName; + this.encoding = xmlReader.Encoding; + ReadXmlDoc(xmlReader); + } else { + string redirectionTarget = GetRedirectionTarget(fileName, xmlReader.GetAttribute("redirect")); + if (redirectionTarget != null) { + Debug.WriteLine("XmlDoc " + fileName + " is redirecting to " + redirectionTarget); + using (FileStream redirectedFs = new FileStream(redirectionTarget, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete)) { + using (XmlTextReader redirectedXmlReader = new XmlTextReader(redirectedFs)) { + redirectedXmlReader.XmlResolver = null; // no DTD resolving + redirectedXmlReader.MoveToContent(); + this.fileName = redirectionTarget; + this.encoding = redirectedXmlReader.Encoding; + ReadXmlDoc(redirectedXmlReader); + } + } + } else { + throw new XmlException("XmlDoc " + fileName + " is redirecting to " + xmlReader.GetAttribute("redirect") + ", but that file was not found."); + } + } + } + } + } + + static string GetRedirectionTarget(string xmlFileName, string target) + { + string programFilesDir = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86); + programFilesDir = AppendDirectorySeparator(programFilesDir); + + string corSysDir = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(); + corSysDir = AppendDirectorySeparator(corSysDir); + + var fileName = target.Replace ("%PROGRAMFILESDIR%", programFilesDir) + .Replace ("%CORSYSDIR%", corSysDir); + if (!Path.IsPathRooted (fileName)) + fileName = Path.Combine (Path.GetDirectoryName (xmlFileName), fileName); + return LookupLocalizedXmlDoc(fileName); + } + + static string AppendDirectorySeparator(string dir) + { + if (dir.EndsWith("\\", StringComparison.Ordinal) || dir.EndsWith("/", StringComparison.Ordinal)) + return dir; + else + return dir + Path.DirectorySeparatorChar; + } + + /// + /// Given the assembly file name, looks up the XML documentation file name. + /// Returns null if no XML documentation file is found. + /// + public static string LookupLocalizedXmlDoc(string fileName) + { + string xmlFileName = Path.ChangeExtension(fileName, ".xml"); + string currentCulture = System.Threading.Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName; + string localizedXmlDocFile = GetLocalizedName(xmlFileName, currentCulture); + + Debug.WriteLine("Try find XMLDoc @" + localizedXmlDocFile); + if (File.Exists(localizedXmlDocFile)) { + return localizedXmlDocFile; + } + Debug.WriteLine("Try find XMLDoc @" + xmlFileName); + if (File.Exists(xmlFileName)) { + return xmlFileName; + } + if (currentCulture != "en") { + string englishXmlDocFile = GetLocalizedName(xmlFileName, "en"); + Debug.WriteLine("Try find XMLDoc @" + englishXmlDocFile); + if (File.Exists(englishXmlDocFile)) { + return englishXmlDocFile; + } + } + return null; + } + + static string GetLocalizedName(string fileName, string language) + { + string localizedXmlDocFile = Path.GetDirectoryName(fileName); + localizedXmlDocFile = Path.Combine(localizedXmlDocFile, language); + localizedXmlDocFile = Path.Combine(localizedXmlDocFile, Path.GetFileName(fileName)); + return localizedXmlDocFile; + } + #endregion + + #region Load / Create Index + void ReadXmlDoc(XmlTextReader reader) + { + //lastWriteDate = File.GetLastWriteTimeUtc(fileName); + // Open up a second file stream for the line<->position mapping + using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete)) { + LinePositionMapper linePosMapper = new LinePositionMapper(fs, encoding); + List indexList = new List(); + while (reader.Read()) { + if (reader.IsStartElement()) { + switch (reader.LocalName) { + case "members": + ReadMembersSection(reader, linePosMapper, indexList); + break; + } + } + } + indexList.Sort(); + this.index = indexList.ToArray(); // volatile write + } + } + + sealed class LinePositionMapper + { + readonly FileStream fs; + readonly Decoder decoder; + int currentLine = 1; + + // buffers for use with Decoder: + byte[] input = new byte[1]; + char[] output = new char[1]; + + public LinePositionMapper(FileStream fs, Encoding encoding) + { + this.decoder = encoding.GetDecoder(); + this.fs = fs; + } + + public int GetPositionForLine(int line) + { + Debug.Assert(line >= currentLine); + while (line > currentLine) { + int b = fs.ReadByte(); + if (b < 0) + throw new EndOfStreamException(); + int bytesUsed, charsUsed; + bool completed; + input[0] = (byte)b; + decoder.Convert(input, 0, 1, output, 0, 1, false, out bytesUsed, out charsUsed, out completed); + Debug.Assert(bytesUsed == 1); + if (charsUsed == 1 && output[0] == '\n') { + currentLine++; + } + } + return checked((int)fs.Position); + } + } + + static void ReadMembersSection(XmlTextReader reader, LinePositionMapper linePosMapper, List indexList) + { + while (reader.Read()) { + switch (reader.NodeType) { + case XmlNodeType.EndElement: + if (reader.LocalName == "members") { + return; + } + break; + case XmlNodeType.Element: + if (reader.LocalName == "member") { + int pos = linePosMapper.GetPositionForLine(reader.LineNumber) + Math.Max(reader.LinePosition - 2, 0); + string memberAttr = reader.GetAttribute("name"); + if (memberAttr != null) + indexList.Add(new IndexEntry(GetHashCode(memberAttr), pos)); + reader.Skip(); + } + break; + } + } + } + + /// + /// Hash algorithm used for the index. + /// This is a custom implementation so that old index files work correctly + /// even when the .NET string.GetHashCode implementation changes + /// (e.g. due to .NET 4.5 hash randomization) + /// + static int GetHashCode(string key) + { + unchecked { + int h = 0; + foreach (char c in key) { + h = (h << 5) - h + c; + } + return h; + } + } + #endregion + + #region GetDocumentation + /// + /// Get the documentation for the member with the specified documentation key. + /// + public string GetDocumentation(string key) + { + if (key == null) + throw new ArgumentNullException("key"); + return GetDocumentation(key, true); + } + + string GetDocumentation(string key, bool allowReload) + { + int hashcode = GetHashCode(key); + var index = this.index; // read volatile field + // index is sorted, so we can use binary search + int m = Array.BinarySearch(index, new IndexEntry(hashcode, 0)); + if (m < 0) + return null; + // correct hash code found. + // possibly there are multiple items with the same hash, so go to the first. + while (--m >= 0 && index[m].HashCode == hashcode); + // m is now 1 before the first item with the correct hash + + XmlDocumentationCache cache = this.cache; + lock (cache) { + string val; + if (!cache.TryGet(key, out val)) { + try { + // go through all items that have the correct hash + while (++m < index.Length && index[m].HashCode == hashcode) { + val = LoadDocumentation(key, index[m].PositionInFile); + if (val != null) + break; + } + // cache the result (even if it is null) + cache.Add(key, val); + } catch (IOException) { + // may happen if the documentation file was deleted/is inaccessible/changed (EndOfStreamException) + return allowReload ? ReloadAndGetDocumentation(key) : null; + } catch (XmlException) { + // may happen if the documentation file was changed so that the file position no longer starts on a valid XML element + return allowReload ? ReloadAndGetDocumentation(key) : null; + } + } + return val; + } + } + + string ReloadAndGetDocumentation(string key) + { + try { + // Reload the index + using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete)) { + using (XmlTextReader xmlReader = new XmlTextReader(fs)) { + xmlReader.XmlResolver = null; // no DTD resolving + xmlReader.MoveToContent(); + ReadXmlDoc(xmlReader); + } + } + } catch (IOException) { + // Ignore errors on reload; IEntity.Documentation callers aren't prepared to handle exceptions + this.index = new IndexEntry[0]; // clear index to avoid future load attempts + return null; + } catch (XmlException) { + this.index = new IndexEntry[0]; // clear index to avoid future load attempts + return null; + } + return GetDocumentation(key, allowReload: false); // prevent infinite reload loops + } + #endregion + + #region GetDocumentation for entity + /// + public DocumentationComment GetDocumentation(IEntity entity) + { + string xmlDoc = GetDocumentation(IdStringProvider.GetIdString(entity)); + if (xmlDoc != null) { + return new DocumentationComment(new StringTextSource(xmlDoc), new SimpleTypeResolveContext(entity)); + } else { + return null; + } + } + #endregion + + #region Load / Read XML + string LoadDocumentation(string key, int positionInFile) + { + using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete)) { + fs.Position = positionInFile; + var context = new XmlParserContext(null, null, null, XmlSpace.None) { Encoding = encoding }; + using (XmlTextReader r = new XmlTextReader(fs, XmlNodeType.Element, context)) { + r.XmlResolver = null; // no DTD resolving + while (r.Read()) { + if (r.NodeType == XmlNodeType.Element) { + string memberAttr = r.GetAttribute("name"); + if (memberAttr == key) { + return r.ReadInnerXml(); + } else { + return null; + } + } + } + return null; + } + } + } + #endregion + + public virtual void OnDeserialization(object sender) + { + cache = new XmlDocumentationCache(); + } + } +} diff --git a/ICSharpCode.Decompiler/Editor/IDocument.cs b/ICSharpCode.Decompiler/Editor/IDocument.cs new file mode 100644 index 000000000..b18732c05 --- /dev/null +++ b/ICSharpCode.Decompiler/Editor/IDocument.cs @@ -0,0 +1,205 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.Editor +{ + /// + /// A document representing a source code file for refactoring. + /// Line and column counting starts at 1. + /// Offset counting starts at 0. + /// + public interface IDocument : ITextSource, IServiceProvider + { + /// + /// Creates an immutable snapshot of this document. + /// + IDocument CreateDocumentSnapshot(); + + /// + /// Gets/Sets the text of the whole document.. + /// + new string Text { get; set; } // hides ITextSource.Text to add the setter + + /// + /// This event is called directly before a change is applied to the document. + /// + /// + /// It is invalid to modify the document within this event handler. + /// Aborting the change (by throwing an exception) is likely to cause corruption of data structures + /// that listen to the Changing and Changed events. + /// + event EventHandler TextChanging; + + /// + /// This event is called directly after a change is applied to the document. + /// + /// + /// It is invalid to modify the document within this event handler. + /// Aborting the event handler (by throwing an exception) is likely to cause corruption of data structures + /// that listen to the Changing and Changed events. + /// + event EventHandler TextChanged; + + /// + /// This event is called after a group of changes is completed. + /// + /// + event EventHandler ChangeCompleted; + + /// + /// Gets the number of lines in the document. + /// + int LineCount { get; } + + /// + /// Gets the document line with the specified number. + /// + /// The number of the line to retrieve. The first line has number 1. + IDocumentLine GetLineByNumber(int lineNumber); + + /// + /// Gets the document line that contains the specified offset. + /// + IDocumentLine GetLineByOffset(int offset); + + /// + /// Gets the offset from a text location. + /// + /// + int GetOffset(int line, int column); + + /// + /// Gets the offset from a text location. + /// + /// + int GetOffset(TextLocation location); + + /// + /// Gets the location from an offset. + /// + /// + TextLocation GetLocation(int offset); + + /// + /// Inserts text. + /// + /// The offset at which the text is inserted. + /// The new text. + /// + /// Anchors positioned exactly at the insertion offset will move according to their movement type. + /// For AnchorMovementType.Default, they will move behind the inserted text. + /// The caret will also move behind the inserted text. + /// + void Insert(int offset, string text); + + /// + /// Inserts text. + /// + /// The offset at which the text is inserted. + /// The new text. + /// + /// Anchors positioned exactly at the insertion offset will move according to their movement type. + /// For AnchorMovementType.Default, they will move behind the inserted text. + /// The caret will also move behind the inserted text. + /// + void Insert(int offset, ITextSource text); + + /// + /// Inserts text. + /// + /// The offset at which the text is inserted. + /// The new text. + /// + /// Anchors positioned exactly at the insertion offset will move according to the anchor's movement type. + /// For AnchorMovementType.Default, they will move according to the movement type specified by this parameter. + /// The caret will also move according to the parameter. + /// + void Insert(int offset, string text, AnchorMovementType defaultAnchorMovementType); + + /// + /// Inserts text. + /// + /// The offset at which the text is inserted. + /// The new text. + /// + /// Anchors positioned exactly at the insertion offset will move according to the anchor's movement type. + /// For AnchorMovementType.Default, they will move according to the movement type specified by this parameter. + /// The caret will also move according to the parameter. + /// + void Insert(int offset, ITextSource text, AnchorMovementType defaultAnchorMovementType); + + /// + /// Removes text. + /// + /// Starting offset of the text to be removed. + /// Length of the text to be removed. + void Remove(int offset, int length); + + /// + /// Replaces text. + /// + /// The starting offset of the text to be replaced. + /// The length of the text to be replaced. + /// The new text. + void Replace(int offset, int length, string newText); + + /// + /// Replaces text. + /// + /// The starting offset of the text to be replaced. + /// The length of the text to be replaced. + /// The new text. + void Replace(int offset, int length, ITextSource newText); + + /// + /// Make the document combine the following actions into a single + /// action for undo purposes. + /// + void StartUndoableAction(); + + /// + /// Ends the undoable action started with . + /// + void EndUndoableAction(); + + /// + /// Creates an undo group. Dispose the returned value to close the undo group. + /// + /// An object that closes the undo group when Dispose() is called. + IDisposable OpenUndoGroup(); + + /// + /// Creates a new at the specified offset. + /// + /// + ITextAnchor CreateAnchor(int offset); + + /// + /// Gets the name of the file the document is stored in. + /// Could also be a non-existent dummy file name or null if no name has been set. + /// + string FileName { get; } + + /// + /// Fired when the file name of the document changes. + /// + event EventHandler FileNameChanged; + } +} diff --git a/ICSharpCode.Decompiler/Editor/IDocumentLine.cs b/ICSharpCode.Decompiler/Editor/IDocumentLine.cs new file mode 100644 index 000000000..e10dc4ebb --- /dev/null +++ b/ICSharpCode.Decompiler/Editor/IDocumentLine.cs @@ -0,0 +1,60 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.Editor +{ + /// + /// A line inside a . + /// + public interface IDocumentLine : ISegment + { + /// + /// Gets the length of this line, including the line delimiter. + /// + int TotalLength { get; } + + /// + /// Gets the length of the line terminator. + /// Returns 1 or 2; or 0 at the end of the document. + /// + int DelimiterLength { get; } + + /// + /// Gets the number of this line. + /// The first line has the number 1. + /// + int LineNumber { get; } + + /// + /// Gets the previous line. Returns null if this is the first line in the document. + /// + IDocumentLine PreviousLine { get; } + + /// + /// Gets the next line. Returns null if this is the last line in the document. + /// + IDocumentLine NextLine { get; } + + /// + /// Gets whether the line was deleted. + /// + bool IsDeleted { get; } + } +} diff --git a/ICSharpCode.Decompiler/Editor/ISegment.cs b/ICSharpCode.Decompiler/Editor/ISegment.cs new file mode 100644 index 000000000..58a84fea4 --- /dev/null +++ b/ICSharpCode.Decompiler/Editor/ISegment.cs @@ -0,0 +1,71 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.Editor +{ + /// + /// An (Offset,Length)-pair. + /// + public interface ISegment + { + /// + /// Gets the start offset of the segment. + /// + int Offset { get; } + + /// + /// Gets the length of the segment. + /// + /// For line segments (IDocumentLine), the length does not include the line delimeter. + int Length { get; } + + /// + /// Gets the end offset of the segment. + /// + /// EndOffset = Offset + Length; + int EndOffset { get; } + } + + /// + /// Extension methods for . + /// + public static class ISegmentExtensions + { + /// + /// Gets whether fully contains the specified segment. + /// + /// + /// Use segment.Contains(offset, 0) to detect whether a segment (end inclusive) contains offset; + /// use segment.Contains(offset, 1) to detect whether a segment (end exclusive) contains offset. + /// + public static bool Contains (this ISegment segment, int offset, int length) + { + return segment.Offset <= offset && offset + length <= segment.EndOffset; + } + + /// + /// Gets whether fully contains the specified segment. + /// + public static bool Contains (this ISegment thisSegment, ISegment segment) + { + return segment != null && thisSegment.Offset <= segment.Offset && segment.EndOffset <= thisSegment.EndOffset; + } + } +} diff --git a/ICSharpCode.Decompiler/Editor/ITextAnchor.cs b/ICSharpCode.Decompiler/Editor/ITextAnchor.cs new file mode 100644 index 000000000..cf61db1cc --- /dev/null +++ b/ICSharpCode.Decompiler/Editor/ITextAnchor.cs @@ -0,0 +1,139 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.Editor +{ + /// + /// The TextAnchor class references an offset (a position between two characters). + /// It automatically updates the offset when text is inserted/removed in front of the anchor. + /// + /// + /// Use the property to get the offset from a text anchor. + /// Use the method to create an anchor from an offset. + /// + /// + /// The document will automatically update all text anchors; and because it uses weak references to do so, + /// the garbage collector can simply collect the anchor object when you don't need it anymore. + /// + /// Moreover, the document is able to efficiently update a large number of anchors without having to look + /// at each anchor object individually. Updating the offsets of all anchors usually only takes time logarithmic + /// to the number of anchors. Retrieving the property also runs in O(lg N). + /// + /// + /// Usage: + /// TextAnchor anchor = document.CreateAnchor(offset); + /// ChangeMyDocument(); + /// int newOffset = anchor.Offset; + /// + /// + public interface ITextAnchor + { + /// + /// Gets the text location of this anchor. + /// + /// Thrown when trying to get the Offset from a deleted anchor. + TextLocation Location { get; } + + /// + /// Gets the offset of the text anchor. + /// + /// Thrown when trying to get the Offset from a deleted anchor. + int Offset { get; } + + /// + /// Controls how the anchor moves. + /// + /// Anchor movement is ambiguous if text is inserted exactly at the anchor's location. + /// Does the anchor stay before the inserted text, or does it move after it? + /// The property will be used to determine which of these two options the anchor will choose. + /// The default value is . + AnchorMovementType MovementType { get; set; } + + /// + /// + /// Specifies whether the anchor survives deletion of the text containing it. + /// + /// false: The anchor is deleted when the a selection that includes the anchor is deleted. + /// true: The anchor is not deleted. + /// + /// + /// + bool SurviveDeletion { get; set; } + + /// + /// Gets whether the anchor was deleted. + /// + /// + /// When a piece of text containing an anchor is removed, then that anchor will be deleted. + /// First, the property is set to true on all deleted anchors, + /// then the events are raised. + /// You cannot retrieve the offset from an anchor that has been deleted. + /// This deletion behavior might be useful when using anchors for building a bookmark feature, + /// but in other cases you want to still be able to use the anchor. For those cases, set = true. + /// + bool IsDeleted { get; } + + /// + /// Occurs after the anchor was deleted. + /// + /// + /// + /// Due to the 'weak reference' nature of text anchors, you will receive + /// the Deleted event only while your code holds a reference to the TextAnchor object. + /// + /// + event EventHandler Deleted; + + /// + /// Gets the line number of the anchor. + /// + /// Thrown when trying to get the Offset from a deleted anchor. + int Line { get; } + + /// + /// Gets the column number of this anchor. + /// + /// Thrown when trying to get the Offset from a deleted anchor. + int Column { get; } + } + + /// + /// Defines how a text anchor moves. + /// + public enum AnchorMovementType + { + /// + /// When text is inserted at the anchor position, the type of the insertion + /// determines where the caret moves to. For normal insertions, the anchor will move + /// after the inserted text. + /// + Default, + /// + /// Behaves like a start marker - when text is inserted at the anchor position, the anchor will stay + /// before the inserted text. + /// + BeforeInsertion, + /// + /// Behave like an end marker - when text is insered at the anchor position, the anchor will move + /// after the inserted text. + /// + AfterInsertion + } +} diff --git a/ICSharpCode.Decompiler/Editor/ITextPasteHandler.cs b/ICSharpCode.Decompiler/Editor/ITextPasteHandler.cs new file mode 100644 index 000000000..3e2a11c71 --- /dev/null +++ b/ICSharpCode.Decompiler/Editor/ITextPasteHandler.cs @@ -0,0 +1,51 @@ +// ITextPasteHandler.cs +// +// Author: +// Mike Krüger +// +// Copyright (c) 2008 Novell, Inc (http://www.novell.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. + +namespace ICSharpCode.NRefactory.Editor +{ + /// + /// The text paste handler can do formattings to a text that is about to be pasted + /// into the text document. + /// + public interface ITextPasteHandler + { + /// + /// Formats plain text that is inserted at a specified offset. + /// + /// + /// The text that will get inserted at that position. + /// + /// The offset where the text will be inserted. + /// The text to be inserted. + /// Additional data in case the text was copied from a Mono.TextEditor. + string FormatPlainText(int offset, string text, byte[] copyData); + + /// + /// Gets the copy data for a specific segment inside the document. This can contain additional information. + /// + /// The text segment that is about to be copied. + byte[] GetCopyData(ISegment segment); + } +} diff --git a/ICSharpCode.Decompiler/Editor/ITextSource.cs b/ICSharpCode.Decompiler/Editor/ITextSource.cs new file mode 100644 index 000000000..32b0f97ae --- /dev/null +++ b/ICSharpCode.Decompiler/Editor/ITextSource.cs @@ -0,0 +1,218 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.IO; + +namespace ICSharpCode.NRefactory.Editor +{ + /// + /// A read-only view on a (potentially mutable) text source. + /// The IDocument interface derives from this interface. + /// + public interface ITextSource + { + /// + /// Gets a version identifier for this text source. + /// Returns null for unversioned text sources. + /// + ITextSourceVersion Version { get; } + + /// + /// Creates an immutable snapshot of this text source. + /// Unlike all other methods in this interface, this method is thread-safe. + /// + ITextSource CreateSnapshot(); + + /// + /// Creates an immutable snapshot of a part of this text source. + /// Unlike all other methods in this interface, this method is thread-safe. + /// + ITextSource CreateSnapshot(int offset, int length); + + /// + /// Creates a new TextReader to read from this text source. + /// + TextReader CreateReader(); + + /// + /// Creates a new TextReader to read from this text source. + /// + TextReader CreateReader(int offset, int length); + + /// + /// Gets the total text length. + /// + /// The length of the text, in characters. + /// This is the same as Text.Length, but is more efficient because + /// it doesn't require creating a String object. + int TextLength { get; } + + /// + /// Gets the whole text as string. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")] + string Text { get; } + + /// + /// Gets a character at the specified position in the document. + /// + /// The index of the character to get. + /// Offset is outside the valid range (0 to TextLength-1). + /// The character at the specified position. + /// This is the same as Text[offset], but is more efficient because + /// it doesn't require creating a String object. + char GetCharAt(int offset); + + /// + /// Retrieves the text for a portion of the document. + /// + /// offset or length is outside the valid range. + /// This is the same as Text.Substring, but is more efficient because + /// it doesn't require creating a String object for the whole document. + string GetText(int offset, int length); + + /// + /// Retrieves the text for a portion of the document. + /// + /// offset or length is outside the valid range. + string GetText(ISegment segment); + + /// + /// Writes the text from this document into the TextWriter. + /// + void WriteTextTo(TextWriter writer); + + /// + /// Writes the text from this document into the TextWriter. + /// + void WriteTextTo(TextWriter writer, int offset, int length); + + /// + /// Gets the index of the first occurrence of the character in the specified array. + /// + /// Character to search for + /// Start index of the area to search. + /// Length of the area to search. + /// The first index where the character was found; or -1 if no occurrence was found. + int IndexOf(char c, int startIndex, int count); + + /// + /// Gets the index of the first occurrence of any character in the specified array. + /// + /// Characters to search for + /// Start index of the area to search. + /// Length of the area to search. + /// The first index where any character was found; or -1 if no occurrence was found. + int IndexOfAny(char[] anyOf, int startIndex, int count); + + /// + /// Gets the index of the first occurrence of the specified search text in this text source. + /// + /// The search text + /// Start index of the area to search. + /// Length of the area to search. + /// String comparison to use. + /// The first index where the search term was found; or -1 if no occurrence was found. + int IndexOf(string searchText, int startIndex, int count, StringComparison comparisonType); + + /// + /// Gets the index of the last occurrence of the specified character in this text source. + /// + /// The search character + /// Start index of the area to search. + /// Length of the area to search. + /// The last index where the search term was found; or -1 if no occurrence was found. + /// The search proceeds backwards from (startIndex+count) to startIndex. + /// This is different than the meaning of the parameters on string.LastIndexOf! + int LastIndexOf(char c, int startIndex, int count); + + /// + /// Gets the index of the last occurrence of the specified search text in this text source. + /// + /// The search text + /// Start index of the area to search. + /// Length of the area to search. + /// String comparison to use. + /// The last index where the search term was found; or -1 if no occurrence was found. + /// The search proceeds backwards from (startIndex+count) to startIndex. + /// This is different than the meaning of the parameters on string.LastIndexOf! + int LastIndexOf(string searchText, int startIndex, int count, StringComparison comparisonType); + + /* What about: + void Insert (int offset, string value); + void Remove (int offset, int count); + void Remove (ISegment segment); + + void Replace (int offset, int count, string value); + + Or more search operations: + + IEnumerable SearchForward (string pattern, int startIndex); + IEnumerable SearchForwardIgnoreCase (string pattern, int startIndex); + + IEnumerable SearchBackward (string pattern, int startIndex); + IEnumerable SearchBackwardIgnoreCase (string pattern, int startIndex); + */ + } + + /// + /// Represents a version identifier for a text source. + /// + /// + /// Verions can be used to efficiently detect whether a document has changed and needs reparsing; + /// or even to implement incremental parsers. + /// It is a separate class from ITextSource to allow the GC to collect the text source while + /// the version checkpoint is still in use. + /// + public interface ITextSourceVersion + { + /// + /// Gets whether this checkpoint belongs to the same document as the other checkpoint. + /// + /// + /// Returns false when given null. + /// + bool BelongsToSameDocumentAs(ITextSourceVersion other); + + /// + /// Compares the age of this checkpoint to the other checkpoint. + /// + /// This method is thread-safe. + /// Raised if 'other' belongs to a different document than this version. + /// -1 if this version is older than . + /// 0 if this version instance represents the same version as . + /// 1 if this version is newer than . + int CompareAge(ITextSourceVersion other); + + /// + /// Gets the changes from this checkpoint to the other checkpoint. + /// If 'other' is older than this checkpoint, reverse changes are calculated. + /// + /// This method is thread-safe. + /// Raised if 'other' belongs to a different document than this checkpoint. + IEnumerable GetChangesTo(ITextSourceVersion other); + + /// + /// Calculates where the offset has moved in the other buffer version. + /// + /// Raised if 'other' belongs to a different document than this checkpoint. + int MoveOffsetTo(ITextSourceVersion other, int oldOffset, AnchorMovementType movement = AnchorMovementType.Default); + } +} diff --git a/ICSharpCode.Decompiler/Editor/ReadOnlyDocument.cs b/ICSharpCode.Decompiler/Editor/ReadOnlyDocument.cs new file mode 100644 index 000000000..6770d4a8b --- /dev/null +++ b/ICSharpCode.Decompiler/Editor/ReadOnlyDocument.cs @@ -0,0 +1,447 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.Editor +{ + /// + /// Read-only implementation of . + /// + [Serializable] + public sealed class ReadOnlyDocument : IDocument + { + readonly ITextSource textSource; + readonly string fileName; + int[] lines; + + static readonly char[] newline = { '\r', '\n' }; + + /// + /// Creates a new ReadOnlyDocument from the given text source. + /// + public ReadOnlyDocument(ITextSource textSource) + { + if (textSource == null) + throw new ArgumentNullException("textSource"); + // ensure that underlying buffer is immutable + this.textSource = textSource.CreateSnapshot(); + List lines = new List(); + lines.Add(0); + int offset = 0; + int textLength = textSource.TextLength; + while ((offset = textSource.IndexOfAny(newline, offset, textLength - offset)) >= 0) { + offset++; + if (textSource.GetCharAt(offset - 1) == '\r' && offset < textLength && textSource.GetCharAt(offset) == '\n') { + offset++; + } + lines.Add(offset); + } + this.lines = lines.ToArray(); + } + + /// + /// Creates a new ReadOnlyDocument from the given string. + /// + public ReadOnlyDocument(string text) + : this(new StringTextSource(text)) + { + } + + /// + /// Creates a new ReadOnlyDocument from the given text source; + /// and sets IDocument.FileName to the specified file name. + /// + public ReadOnlyDocument(ITextSource textSource, string fileName) + : this(textSource) + { + this.fileName = fileName; + } + + /// + public IDocumentLine GetLineByNumber(int lineNumber) + { + if (lineNumber < 1 || lineNumber > lines.Length) + throw new ArgumentOutOfRangeException("lineNumber", lineNumber, "Value must be between 1 and " + lines.Length); + return new ReadOnlyDocumentLine(this, lineNumber); + } + + sealed class ReadOnlyDocumentLine : IDocumentLine + { + readonly ReadOnlyDocument doc; + readonly int lineNumber; + readonly int offset, endOffset; + + public ReadOnlyDocumentLine(ReadOnlyDocument doc, int lineNumber) + { + this.doc = doc; + this.lineNumber = lineNumber; + this.offset = doc.GetStartOffset(lineNumber); + this.endOffset = doc.GetEndOffset(lineNumber); + } + + public override int GetHashCode() + { + return doc.GetHashCode() ^ lineNumber; + } + + public override bool Equals(object obj) + { + ReadOnlyDocumentLine other = obj as ReadOnlyDocumentLine; + return other != null && doc == other.doc && lineNumber == other.lineNumber; + } + + public int Offset { + get { return offset; } + } + + public int Length { + get { return endOffset - offset; } + } + + public int EndOffset { + get { return endOffset; } + } + + public int TotalLength { + get { + return doc.GetTotalEndOffset(lineNumber) - offset; + } + } + + public int DelimiterLength { + get { + return doc.GetTotalEndOffset(lineNumber) - endOffset; + } + } + + public int LineNumber { + get { return lineNumber; } + } + + public IDocumentLine PreviousLine { + get { + if (lineNumber == 1) + return null; + else + return new ReadOnlyDocumentLine(doc, lineNumber - 1); + } + } + + public IDocumentLine NextLine { + get { + if (lineNumber == doc.LineCount) + return null; + else + return new ReadOnlyDocumentLine(doc, lineNumber + 1); + } + } + + public bool IsDeleted { + get { return false; } + } + } + + int GetStartOffset(int lineNumber) + { + return lines[lineNumber-1]; + } + + int GetTotalEndOffset(int lineNumber) + { + return lineNumber < lines.Length ? lines[lineNumber] : textSource.TextLength; + } + + int GetEndOffset(int lineNumber) + { + if (lineNumber == lines.Length) + return textSource.TextLength; + int off = lines[lineNumber] - 1; + if (off > 0 && textSource.GetCharAt(off - 1) == '\r' && textSource.GetCharAt(off) == '\n') + off--; + return off; + } + + /// + public IDocumentLine GetLineByOffset(int offset) + { + return GetLineByNumber(GetLineNumberForOffset(offset)); + } + + int GetLineNumberForOffset(int offset) + { + int r = Array.BinarySearch(lines, offset); + return r < 0 ? ~r : r + 1; + } + + /// + public int GetOffset(int line, int column) + { + if (line < 1 || line > lines.Length) + throw new ArgumentOutOfRangeException("line", line, "Value must be between 1 and " + lines.Length); + int lineStart = GetStartOffset(line); + if (column <= 1) + return lineStart; + int lineEnd = GetEndOffset(line); + if (column - 1 >= lineEnd - lineStart) + return lineEnd; + return lineStart + column - 1; + } + + /// + public int GetOffset(TextLocation location) + { + return GetOffset(location.Line, location.Column); + } + + /// + public TextLocation GetLocation(int offset) + { + if (offset < 0 || offset > textSource.TextLength) + throw new ArgumentOutOfRangeException("offset", offset, "Value must be between 0 and " + textSource.TextLength); + int line = GetLineNumberForOffset(offset); + return new TextLocation(line, offset-GetStartOffset(line)+1); + } + + /// + public string Text { + get { return textSource.Text; } + set { + throw new NotSupportedException(); + } + } + + /// + public int LineCount { + get { return lines.Length; } + } + + /// + public ITextSourceVersion Version { + get { return textSource.Version; } + } + + /// + public int TextLength { + get { return textSource.TextLength; } + } + + event EventHandler IDocument.TextChanging { add {} remove {} } + + event EventHandler IDocument.TextChanged { add {} remove {} } + + event EventHandler IDocument.ChangeCompleted { add {} remove {} } + + void IDocument.Insert(int offset, string text) + { + throw new NotSupportedException(); + } + + void IDocument.Insert(int offset, string text, AnchorMovementType defaultAnchorMovementType) + { + throw new NotSupportedException(); + } + + void IDocument.Remove(int offset, int length) + { + throw new NotSupportedException(); + } + + void IDocument.Replace(int offset, int length, string newText) + { + throw new NotSupportedException(); + } + + void IDocument.Insert(int offset, ITextSource text) + { + throw new NotSupportedException(); + } + + void IDocument.Insert(int offset, ITextSource text, AnchorMovementType defaultAnchorMovementType) + { + throw new NotSupportedException(); + } + + void IDocument.Replace(int offset, int length, ITextSource newText) + { + throw new NotSupportedException(); + } + + void IDocument.StartUndoableAction() + { + } + + void IDocument.EndUndoableAction() + { + } + + IDisposable IDocument.OpenUndoGroup() + { + return null; + } + + /// + public ITextAnchor CreateAnchor(int offset) + { + return new ReadOnlyDocumentTextAnchor(GetLocation(offset), offset); + } + + sealed class ReadOnlyDocumentTextAnchor : ITextAnchor + { + readonly TextLocation location; + readonly int offset; + + public ReadOnlyDocumentTextAnchor(TextLocation location, int offset) + { + this.location = location; + this.offset = offset; + } + + public event EventHandler Deleted { add {} remove {} } + + public TextLocation Location { + get { return location; } + } + + public int Offset { + get { return offset; } + } + + public AnchorMovementType MovementType { get; set; } + + public bool SurviveDeletion { get; set; } + + public bool IsDeleted { + get { return false; } + } + + public int Line { + get { return location.Line; } + } + + public int Column { + get { return location.Column; } + } + } + + /// + public ITextSource CreateSnapshot() + { + return textSource; // textBuffer is immutable + } + + /// + public ITextSource CreateSnapshot(int offset, int length) + { + return textSource.CreateSnapshot(offset, length); + } + + /// + public IDocument CreateDocumentSnapshot() + { + return this; // ReadOnlyDocument is immutable + } + + /// + public System.IO.TextReader CreateReader() + { + return textSource.CreateReader(); + } + + /// + public System.IO.TextReader CreateReader(int offset, int length) + { + return textSource.CreateReader(offset, length); + } + + /// + public void WriteTextTo(System.IO.TextWriter writer) + { + textSource.WriteTextTo(writer); + } + + /// + public void WriteTextTo(System.IO.TextWriter writer, int offset, int length) + { + textSource.WriteTextTo(writer, offset, length); + } + + /// + public char GetCharAt(int offset) + { + return textSource.GetCharAt(offset); + } + + /// + public string GetText(int offset, int length) + { + return textSource.GetText(offset, length); + } + + /// + public string GetText(ISegment segment) + { + return textSource.GetText(segment); + } + + /// + public int IndexOf(char c, int startIndex, int count) + { + return textSource.IndexOf(c, startIndex, count); + } + + /// + public int IndexOfAny(char[] anyOf, int startIndex, int count) + { + return textSource.IndexOfAny(anyOf, startIndex, count); + } + + /// + public int IndexOf(string searchText, int startIndex, int count, StringComparison comparisonType) + { + return textSource.IndexOf(searchText, startIndex, count, comparisonType); + } + + /// + public int LastIndexOf(char c, int startIndex, int count) + { + return textSource.LastIndexOf(c, startIndex, count); + } + + /// + public int LastIndexOf(string searchText, int startIndex, int count, StringComparison comparisonType) + { + return textSource.LastIndexOf(searchText, startIndex, count, comparisonType); + } + + object IServiceProvider.GetService(Type serviceType) + { + return null; + } + + /// + /// Will never be raised on . + public event EventHandler FileNameChanged { add {} remove {} } + + /// + public string FileName { + get { return fileName; } + } + } +} diff --git a/ICSharpCode.Decompiler/Editor/StringBuilderDocument.cs b/ICSharpCode.Decompiler/Editor/StringBuilderDocument.cs new file mode 100644 index 000000000..5f234687b --- /dev/null +++ b/ICSharpCode.Decompiler/Editor/StringBuilderDocument.cs @@ -0,0 +1,493 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.IO; +using System.Text; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.Editor +{ + /// + /// Document based on a string builder. + /// This class serves as a reference implementation for the IDocument interface. + /// + public class StringBuilderDocument : IDocument + { + readonly StringBuilder b; + readonly TextSourceVersionProvider versionProvider = new TextSourceVersionProvider(); + + /// + /// Creates a new StringBuilderDocument. + /// + public StringBuilderDocument() + { + b = new StringBuilder(); + } + + /// + /// Creates a new StringBuilderDocument with the specified initial text. + /// + public StringBuilderDocument(string text) + { + if (text == null) + throw new ArgumentNullException("text"); + b = new StringBuilder(text); + } + + /// + /// Creates a new StringBuilderDocument with the initial text copied from the specified text source. + /// + public StringBuilderDocument(ITextSource textSource) + { + if (textSource == null) + throw new ArgumentNullException("textSource"); + b = new StringBuilder(textSource.TextLength); + textSource.WriteTextTo(new StringWriter(b)); + } + + /// + public event EventHandler TextChanging; + + /// + public event EventHandler TextChanged; + + /// + public event EventHandler ChangeCompleted; + + /// + public ITextSourceVersion Version { + get { return versionProvider.CurrentVersion; } + } + + #region Line<->Offset + /// + public int LineCount { + get { return CreateDocumentSnapshot().LineCount; } + } + + /// + public IDocumentLine GetLineByNumber(int lineNumber) + { + return CreateDocumentSnapshot().GetLineByNumber(lineNumber); + } + + /// + public IDocumentLine GetLineByOffset(int offset) + { + return CreateDocumentSnapshot().GetLineByOffset(offset); + } + + /// + public int GetOffset(int line, int column) + { + return CreateDocumentSnapshot().GetOffset(line, column); + } + + /// + public int GetOffset(TextLocation location) + { + return CreateDocumentSnapshot().GetOffset(location); + } + + /// + public TextLocation GetLocation(int offset) + { + return CreateDocumentSnapshot().GetLocation(offset); + } + #endregion + + #region Insert/Remove/Replace + /// + public void Insert(int offset, string text) + { + Replace(offset, 0, text); + } + + /// + public void Insert(int offset, ITextSource text) + { + if (text == null) + throw new ArgumentNullException("text"); + Replace(offset, 0, text.Text); + } + + /// + public void Insert(int offset, string text, AnchorMovementType defaultAnchorMovementType) + { + if (offset < 0 || offset > this.TextLength) + throw new ArgumentOutOfRangeException("offset"); + if (text == null) + throw new ArgumentNullException("text"); + if (defaultAnchorMovementType == AnchorMovementType.BeforeInsertion) + PerformChange(new InsertionWithMovementBefore(offset, text)); + else + Replace(offset, 0, text); + } + + /// + public void Insert(int offset, ITextSource text, AnchorMovementType defaultAnchorMovementType) + { + if (text == null) + throw new ArgumentNullException("text"); + Insert(offset, text.Text, defaultAnchorMovementType); + } + + [Serializable] + sealed class InsertionWithMovementBefore : TextChangeEventArgs + { + public InsertionWithMovementBefore(int offset, string newText) : base(offset, string.Empty, newText) + { + } + + public override int GetNewOffset(int offset, AnchorMovementType movementType) + { + if (offset == this.Offset && movementType == AnchorMovementType.Default) + return offset; + else + return base.GetNewOffset(offset, movementType); + } + } + + /// + public void Remove(int offset, int length) + { + Replace(offset, length, string.Empty); + } + + /// + public void Replace(int offset, int length, string newText) + { + if (offset < 0 || offset > this.TextLength) + throw new ArgumentOutOfRangeException("offset"); + if (length < 0 || length > this.TextLength - offset) + throw new ArgumentOutOfRangeException("length"); + if (newText == null) + throw new ArgumentNullException("newText"); + PerformChange(new TextChangeEventArgs(offset, b.ToString(offset, length), newText)); + } + + /// + public void Replace(int offset, int length, ITextSource newText) + { + if (newText == null) + throw new ArgumentNullException("newText"); + Replace(offset, length, newText.Text); + } + + bool isInChange; + + void PerformChange(TextChangeEventArgs change) + { + // Ensure that all changes take place inside an update group. + // Will also take care of throwing an exception if isInChange is set. + StartUndoableAction(); + try { + isInChange = true; + try { + if (TextChanging != null) + TextChanging(this, change); + + // Perform changes to document and Version property + documentSnapshot = null; + cachedText = null; + b.Remove(change.Offset, change.RemovalLength); + b.Insert(change.Offset, change.InsertedText.Text); + versionProvider.AppendChange(change); + + // Update anchors and fire Deleted events + UpdateAnchors(change); + + if (TextChanged != null) + TextChanged(this, change); + } finally { + isInChange = false; + } + } finally { + EndUndoableAction(); + } + } + #endregion + + #region Undo + int undoGroupNesting = 0; + + /// + public void StartUndoableAction() + { + // prevent changes from within the TextChanging/TextChanged event handlers + if (isInChange) + throw new InvalidOperationException(); + undoGroupNesting++; + } + + /// + public void EndUndoableAction() + { + undoGroupNesting--; + if (undoGroupNesting == 0) { + if (ChangeCompleted != null) + ChangeCompleted(this, EventArgs.Empty); + } + } + + /// + public IDisposable OpenUndoGroup() + { + StartUndoableAction(); + return new CallbackOnDispose(EndUndoableAction); + } + #endregion + + #region CreateSnapshot/CreateReader + ReadOnlyDocument documentSnapshot; + + /// + public IDocument CreateDocumentSnapshot() + { + if (documentSnapshot == null) + documentSnapshot = new ReadOnlyDocument(this, this.FileName); + return documentSnapshot; + } + + /// + public ITextSource CreateSnapshot() + { + return new StringTextSource(this.Text, versionProvider.CurrentVersion); + } + + /// + public ITextSource CreateSnapshot(int offset, int length) + { + return new StringTextSource(GetText(offset, length)); + } + + /// + public TextReader CreateReader() + { + return new StringReader(this.Text); + } + + /// + public TextReader CreateReader(int offset, int length) + { + return new StringReader(GetText(offset, length)); + } + + /// + public void WriteTextTo(TextWriter writer) + { + if (writer == null) + throw new ArgumentNullException("writer"); + writer.Write(this.Text); + } + + /// + public void WriteTextTo(TextWriter writer, int offset, int length) + { + if (writer == null) + throw new ArgumentNullException("writer"); + writer.Write(GetText(offset, length)); + } + #endregion + + #region GetText / IndexOf + string cachedText; + + /// + public string Text { + get { + if (cachedText == null) + cachedText = b.ToString(); + return cachedText; + } + set { + Replace(0, b.Length, value); + } + } + + /// + public int TextLength { + get { return b.Length; } + } + + /// + public char GetCharAt(int offset) + { + return b[offset]; + } + + /// + public string GetText(int offset, int length) + { + return b.ToString(offset, length); + } + + /// + public string GetText(ISegment segment) + { + if (segment == null) + throw new ArgumentNullException("segment"); + return b.ToString(segment.Offset, segment.Length); + } + + /// + public int IndexOf(char c, int startIndex, int count) + { + return this.Text.IndexOf(c, startIndex, count); + } + + /// + public int IndexOfAny(char[] anyOf, int startIndex, int count) + { + return this.Text.IndexOfAny(anyOf, startIndex, count); + } + + /// + public int IndexOf(string searchText, int startIndex, int count, StringComparison comparisonType) + { + return this.Text.IndexOf(searchText, startIndex, count, comparisonType); + } + + /// + public int LastIndexOf(char c, int startIndex, int count) + { + return this.Text.LastIndexOf(c, startIndex + count - 1, count); + } + + /// + public int LastIndexOf(string searchText, int startIndex, int count, StringComparison comparisonType) + { + return this.Text.LastIndexOf(searchText, startIndex + count - 1, count, comparisonType); + } + #endregion + + #region CreateAnchor + readonly List anchors = new List(); + + /// + public ITextAnchor CreateAnchor(int offset) + { + var newAnchor = new SimpleAnchor(this, offset); + for (int i = 0; i < anchors.Count; i++) { + if (!anchors[i].IsAlive) + anchors[i] = new WeakReference(newAnchor); + } + anchors.Add(new WeakReference(newAnchor)); + return newAnchor; + } + + void UpdateAnchors(TextChangeEventArgs change) + { + // First update all anchors, then fire the deleted events. + List deletedAnchors = new List(); + for (int i = 0; i < anchors.Count; i++) { + var anchor = anchors[i].Target as SimpleAnchor; + if (anchor != null) { + anchor.Update(change); + if (anchor.IsDeleted) + deletedAnchors.Add(i); + } + } + deletedAnchors.Reverse(); + foreach (var index in deletedAnchors) { + var anchor = anchors[index].Target as SimpleAnchor; + if (anchor != null) + anchor.RaiseDeletedEvent(); + anchors.RemoveAt(index); + } + } + + sealed class SimpleAnchor : ITextAnchor + { + readonly StringBuilderDocument document; + int offset; + + public SimpleAnchor(StringBuilderDocument document, int offset) + { + this.document = document; + this.offset = offset; + } + + public event EventHandler Deleted; + + public TextLocation Location { + get { + if (IsDeleted) + throw new InvalidOperationException(); + return document.GetLocation(offset); + } + } + + public int Offset { + get { + if (IsDeleted) + throw new InvalidOperationException(); + return offset; + } + } + + public AnchorMovementType MovementType { get; set; } + + public bool SurviveDeletion { get; set; } + + public bool IsDeleted { + get { return offset < 0; } + } + + public void Update(TextChangeEventArgs change) + { + if (SurviveDeletion || offset <= change.Offset || offset >= change.Offset + change.RemovalLength) { + offset = change.GetNewOffset(offset, MovementType); + } else { + offset = -1; + } + } + + public void RaiseDeletedEvent() + { + if (Deleted != null) + Deleted(this, EventArgs.Empty); + } + + public int Line { + get { return this.Location.Line; } + } + + public int Column { + get { return this.Location.Column; } + } + } + #endregion + + /// + public virtual object GetService(Type serviceType) + { + return null; + } + + /// + public virtual event EventHandler FileNameChanged { add {} remove {} } + + /// + public virtual string FileName { + get { return string.Empty; } + } + } +} diff --git a/ICSharpCode.Decompiler/Editor/StringTextSource.cs b/ICSharpCode.Decompiler/Editor/StringTextSource.cs new file mode 100644 index 000000000..e76e531bc --- /dev/null +++ b/ICSharpCode.Decompiler/Editor/StringTextSource.cs @@ -0,0 +1,160 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.IO; + +namespace ICSharpCode.NRefactory.Editor +{ + /// + /// Implements the ITextSource interface using a string. + /// + [Serializable] + public class StringTextSource : ITextSource + { + /// + /// Gets a text source containing the empty string. + /// + public static readonly StringTextSource Empty = new StringTextSource(string.Empty); + + readonly string text; + readonly ITextSourceVersion version; + + /// + /// Creates a new StringTextSource with the given text. + /// + public StringTextSource(string text) + { + if (text == null) + throw new ArgumentNullException("text"); + this.text = text; + } + + /// + /// Creates a new StringTextSource with the given text. + /// + public StringTextSource(string text, ITextSourceVersion version) + { + if (text == null) + throw new ArgumentNullException("text"); + this.text = text; + this.version = version; + } + + /// + public ITextSourceVersion Version { + get { return version; } + } + + /// + public int TextLength { + get { return text.Length; } + } + + /// + public string Text { + get { return text; } + } + + /// + public ITextSource CreateSnapshot() + { + return this; // StringTextSource is immutable + } + + /// + public ITextSource CreateSnapshot(int offset, int length) + { + return new StringTextSource(text.Substring(offset, length)); + } + + /// + public TextReader CreateReader() + { + return new StringReader(text); + } + + /// + public TextReader CreateReader(int offset, int length) + { + return new StringReader(text.Substring(offset, length)); + } + + /// + public void WriteTextTo(TextWriter writer) + { + writer.Write(text); + } + + /// + public void WriteTextTo(TextWriter writer, int offset, int length) + { + writer.Write(text.Substring(offset, length)); + } + + /// + public char GetCharAt(int offset) + { + return text[offset]; + } + + /// + public string GetText(int offset, int length) + { + return text.Substring(offset, length); + } + + /// + public string GetText(ISegment segment) + { + if (segment == null) + throw new ArgumentNullException("segment"); + return text.Substring(segment.Offset, segment.Length); + } + + /// + public int IndexOf(char c, int startIndex, int count) + { + return text.IndexOf(c, startIndex, count); + } + + /// + public int IndexOfAny(char[] anyOf, int startIndex, int count) + { + return text.IndexOfAny(anyOf, startIndex, count); + } + + /// + public int IndexOf(string searchText, int startIndex, int count, StringComparison comparisonType) + { + return text.IndexOf(searchText, startIndex, count, comparisonType); + } + + /// + public int LastIndexOf(char c, int startIndex, int count) + { + return text.LastIndexOf(c, startIndex + count - 1, count); + } + + /// + public int LastIndexOf(string searchText, int startIndex, int count, StringComparison comparisonType) + { + return text.LastIndexOf(searchText, startIndex + count - 1, count, comparisonType); + } + } +} diff --git a/ICSharpCode.Decompiler/Editor/TextChangeEventArgs.cs b/ICSharpCode.Decompiler/Editor/TextChangeEventArgs.cs new file mode 100644 index 000000000..442e7d591 --- /dev/null +++ b/ICSharpCode.Decompiler/Editor/TextChangeEventArgs.cs @@ -0,0 +1,118 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.Editor +{ + /// + /// Describes a change of the document text. + /// This class is thread-safe. + /// + [Serializable] + public class TextChangeEventArgs : EventArgs + { + readonly int offset; + readonly ITextSource removedText; + readonly ITextSource insertedText; + + /// + /// The offset at which the change occurs. + /// + public int Offset { + get { return offset; } + } + + /// + /// The text that was removed. + /// + public ITextSource RemovedText { + get { return removedText; } + } + + /// + /// The number of characters removed. + /// + public int RemovalLength { + get { return removedText.TextLength; } + } + + /// + /// The text that was inserted. + /// + public ITextSource InsertedText { + get { return insertedText; } + } + + /// + /// The number of characters inserted. + /// + public int InsertionLength { + get { return insertedText.TextLength; } + } + + /// + /// Creates a new TextChangeEventArgs object. + /// + public TextChangeEventArgs(int offset, string removedText, string insertedText) + { + if (offset < 0) + throw new ArgumentOutOfRangeException("offset", offset, "offset must not be negative"); + this.offset = offset; + this.removedText = removedText != null ? new StringTextSource(removedText) : StringTextSource.Empty; + this.insertedText = insertedText != null ? new StringTextSource(insertedText) : StringTextSource.Empty; + } + + /// + /// Creates a new TextChangeEventArgs object. + /// + public TextChangeEventArgs(int offset, ITextSource removedText, ITextSource insertedText) + { + if (offset < 0) + throw new ArgumentOutOfRangeException("offset", offset, "offset must not be negative"); + this.offset = offset; + this.removedText = removedText ?? StringTextSource.Empty; + this.insertedText = insertedText ?? StringTextSource.Empty; + } + + /// + /// Gets the new offset where the specified offset moves after this document change. + /// + public virtual int GetNewOffset(int offset, AnchorMovementType movementType = AnchorMovementType.Default) + { + if (offset >= this.Offset && offset <= this.Offset + this.RemovalLength) { + if (movementType == AnchorMovementType.BeforeInsertion) + return this.Offset; + else + return this.Offset + this.InsertionLength; + } else if (offset > this.Offset) { + return offset + this.InsertionLength - this.RemovalLength; + } else { + return offset; + } + } + + /// + /// Creates TextChangeEventArgs for the reverse change. + /// + public virtual TextChangeEventArgs Invert() + { + return new TextChangeEventArgs(offset, insertedText, removedText); + } + } +} diff --git a/ICSharpCode.Decompiler/Editor/TextSourceVersionProvider.cs b/ICSharpCode.Decompiler/Editor/TextSourceVersionProvider.cs new file mode 100644 index 000000000..b3415c940 --- /dev/null +++ b/ICSharpCode.Decompiler/Editor/TextSourceVersionProvider.cs @@ -0,0 +1,130 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Diagnostics; +using System.Linq; + +namespace ICSharpCode.NRefactory.Editor +{ + /// + /// Provides ITextSourceVersion instances. + /// + public class TextSourceVersionProvider + { + Version currentVersion; + + public TextSourceVersionProvider() + { + this.currentVersion = new Version(this); + } + + /// + /// Gets the current version. + /// + public ITextSourceVersion CurrentVersion { + get { return currentVersion; } + } + + /// + /// Replaces the current version with a new version. + /// + /// Change from current version to new version + public void AppendChange(TextChangeEventArgs change) + { + if (change == null) + throw new ArgumentNullException("change"); + currentVersion.change = change; + currentVersion.next = new Version(currentVersion); + currentVersion = currentVersion.next; + } + + [DebuggerDisplay("Version #{id}")] + sealed class Version : ITextSourceVersion + { + // Reference back to the provider. + // Used to determine if two checkpoints belong to the same document. + readonly TextSourceVersionProvider provider; + // ID used for CompareAge() + readonly int id; + + // the change from this version to the next version + internal TextChangeEventArgs change; + internal Version next; + + internal Version(TextSourceVersionProvider provider) + { + this.provider = provider; + } + + internal Version(Version prev) + { + this.provider = prev.provider; + this.id = unchecked( prev.id + 1 ); + } + + public bool BelongsToSameDocumentAs(ITextSourceVersion other) + { + Version o = other as Version; + return o != null && provider == o.provider; + } + + public int CompareAge(ITextSourceVersion other) + { + if (other == null) + throw new ArgumentNullException("other"); + Version o = other as Version; + if (o == null || provider != o.provider) + throw new ArgumentException("Versions do not belong to the same document."); + // We will allow overflows, but assume that the maximum distance between checkpoints is 2^31-1. + // This is guaranteed on x86 because so many checkpoints don't fit into memory. + return Math.Sign(unchecked( this.id - o.id )); + } + + public IEnumerable GetChangesTo(ITextSourceVersion other) + { + int result = CompareAge(other); + Version o = (Version)other; + if (result < 0) + return GetForwardChanges(o); + else if (result > 0) + return o.GetForwardChanges(this).Reverse().Select(change => change.Invert()); + else + return EmptyList.Instance; + } + + IEnumerable GetForwardChanges(Version other) + { + // Return changes from this(inclusive) to other(exclusive). + for (Version node = this; node != other; node = node.next) { + yield return node.change; + } + } + + public int MoveOffsetTo(ITextSourceVersion other, int oldOffset, AnchorMovementType movement) + { + int offset = oldOffset; + foreach (var e in GetChangesTo(other)) { + offset = e.GetNewOffset(offset, movement); + } + return offset; + } + } + } +} diff --git a/ICSharpCode.Decompiler/Editor/UnicodeNewline.cs b/ICSharpCode.Decompiler/Editor/UnicodeNewline.cs new file mode 100644 index 000000000..5fa8a6b62 --- /dev/null +++ b/ICSharpCode.Decompiler/Editor/UnicodeNewline.cs @@ -0,0 +1,365 @@ +// +// UnicodeNewline.cs +// +// Author: +// Mike Krüger +// +// Copyright (c) 2013 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; + +namespace ICSharpCode.NRefactory +{ + public enum UnicodeNewline { + Unknown, + + /// + /// Line Feed, U+000A + /// + LF = 0x0A, + + + CRLF = 0x0D0A, + + /// + /// Carriage Return, U+000D + /// + CR = 0x0D, + + /// + /// Next Line, U+0085 + /// + NEL = 0x85, + + /// + /// Vertical Tab, U+000B + /// + VT = 0x0B, + + /// + /// Form Feed, U+000C + /// + FF = 0x0C, + + /// + /// Line Separator, U+2028 + /// + LS = 0x2028, + + /// + /// Paragraph Separator, U+2029 + /// + PS = 0x2029 + } + + + /// + /// Defines unicode new lines according to Unicode Technical Report #13 + /// http://www.unicode.org/standard/reports/tr13/tr13-5.html + /// + public static class NewLine + { + /// + /// Carriage Return, U+000D + /// + public const char CR = (char)0x0D; + + /// + /// Line Feed, U+000A + /// + public const char LF = (char)0x0A; + + /// + /// Next Line, U+0085 + /// + public const char NEL = (char)0x85; + + /// + /// Vertical Tab, U+000B + /// + public const char VT = (char)0x0B; + + /// + /// Form Feed, U+000C + /// + public const char FF = (char)0x0C; + + /// + /// Line Separator, U+2028 + /// + public const char LS = (char)0x2028; + + /// + /// Paragraph Separator, U+2029 + /// + public const char PS = (char)0x2029; + + /// + /// Determines if a char is a new line delimiter. + /// + /// 0 == no new line, otherwise it returns either 1 or 2 depending of the length of the delimiter. + /// The current character. + /// A callback getting the next character (may be null). + public static int GetDelimiterLength (char curChar, Func nextChar = null) + { + if (curChar == CR) { + if (nextChar != null && nextChar () == LF) + return 2; + return 1; + } + + if (curChar == LF || curChar == NEL || curChar == VT || curChar == FF || curChar == LS || curChar == PS) + return 1; + return 0; + } + + /// + /// Determines if a char is a new line delimiter. + /// + /// 0 == no new line, otherwise it returns either 1 or 2 depending of the length of the delimiter. + /// The current character. + /// The next character (if != LF then length will always be 0 or 1). + public static int GetDelimiterLength (char curChar, char nextChar) + { + if (curChar == CR) { + if (nextChar == LF) + return 2; + return 1; + } + + if (curChar == LF || curChar == NEL || curChar == VT || curChar == FF || curChar == LS || curChar == PS) + return 1; + return 0; + } + + + /// + /// Determines if a char is a new line delimiter. + /// + /// 0 == no new line, otherwise it returns either 1 or 2 depending of the length of the delimiter. + /// The current character. + /// The length of the delimiter + /// The type of the delimiter + /// A callback getting the next character (may be null). + public static bool TryGetDelimiterLengthAndType (char curChar, out int length, out UnicodeNewline type, Func nextChar = null) + { + if (curChar == CR) { + if (nextChar != null && nextChar () == LF) { + length = 2; + type = UnicodeNewline.CRLF; + } else { + length = 1; + type = UnicodeNewline.CR; + + } + return true; + } + + switch (curChar) { + case LF: + type = UnicodeNewline.LF; + length = 1; + return true; + case NEL: + type = UnicodeNewline.NEL; + length = 1; + return true; + case VT: + type = UnicodeNewline.VT; + length = 1; + return true; + case FF: + type = UnicodeNewline.FF; + length = 1; + return true; + case LS: + type = UnicodeNewline.LS; + length = 1; + return true; + case PS: + type = UnicodeNewline.PS; + length = 1; + return true; + } + length = -1; + type = UnicodeNewline.Unknown; + return false; + } + + /// + /// Determines if a char is a new line delimiter. + /// + /// 0 == no new line, otherwise it returns either 1 or 2 depending of the length of the delimiter. + /// The current character. + /// The length of the delimiter + /// The type of the delimiter + /// The next character (if != LF then length will always be 0 or 1). + public static bool TryGetDelimiterLengthAndType (char curChar, out int length, out UnicodeNewline type, char nextChar) + { + if (curChar == CR) { + if (nextChar == LF) { + length = 2; + type = UnicodeNewline.CRLF; + } else { + length = 1; + type = UnicodeNewline.CR; + + } + return true; + } + + switch (curChar) { + case LF: + type = UnicodeNewline.LF; + length = 1; + return true; + case NEL: + type = UnicodeNewline.NEL; + length = 1; + return true; + case VT: + type = UnicodeNewline.VT; + length = 1; + return true; + case FF: + type = UnicodeNewline.FF; + length = 1; + return true; + case LS: + type = UnicodeNewline.LS; + length = 1; + return true; + case PS: + type = UnicodeNewline.PS; + length = 1; + return true; + } + length = -1; + type = UnicodeNewline.Unknown; + return false; + } + + /// + /// Gets the new line type of a given char/next char. + /// + /// 0 == no new line, otherwise it returns either 1 or 2 depending of the length of the delimiter. + /// The current character. + /// A callback getting the next character (may be null). + public static UnicodeNewline GetDelimiterType (char curChar, Func nextChar = null) + { + switch (curChar) { + case CR: + if (nextChar != null && nextChar () == LF) + return UnicodeNewline.CRLF; + return UnicodeNewline.CR; + case LF: + return UnicodeNewline.LF; + case NEL: + return UnicodeNewline.NEL; + case VT: + return UnicodeNewline.VT; + case FF: + return UnicodeNewline.FF; + case LS: + return UnicodeNewline.LS; + case PS: + return UnicodeNewline.PS; + } + return UnicodeNewline.Unknown; + } + + /// + /// Gets the new line type of a given char/next char. + /// + /// 0 == no new line, otherwise it returns either 1 or 2 depending of the length of the delimiter. + /// The current character. + /// The next character (if != LF then length will always be 0 or 1). + public static UnicodeNewline GetDelimiterType (char curChar, char nextChar) + { + switch (curChar) { + case CR: + if (nextChar == LF) + return UnicodeNewline.CRLF; + return UnicodeNewline.CR; + case LF: + return UnicodeNewline.LF; + case NEL: + return UnicodeNewline.NEL; + case VT: + return UnicodeNewline.VT; + case FF: + return UnicodeNewline.FF; + case LS: + return UnicodeNewline.LS; + case PS: + return UnicodeNewline.PS; + } + return UnicodeNewline.Unknown; + } + + /// + /// Determines if a char is a new line delimiter. + /// + /// Note that the only 2 char wide new line is CR LF and both chars are new line + /// chars on their own. For most cases GetDelimiterLength is the better choice. + /// + public static bool IsNewLine(char ch) + { + return + ch == NewLine.CR || + ch == NewLine.LF || + ch == NewLine.NEL || + ch == NewLine.VT || + ch == NewLine.FF || + ch == NewLine.LS || + ch == NewLine.PS; + } + + /// + /// Gets the new line as a string. + /// + public static string GetString (UnicodeNewline newLine) + { + switch (newLine) { + case UnicodeNewline.Unknown: + return ""; + case UnicodeNewline.LF: + return "\n"; + case UnicodeNewline.CRLF: + return "\r\n"; + case UnicodeNewline.CR: + return "\r"; + case UnicodeNewline.NEL: + return "\u0085"; + case UnicodeNewline.VT: + return "\u000B"; + case UnicodeNewline.FF: + return "\u000C"; + case UnicodeNewline.LS: + return "\u2028"; + case UnicodeNewline.PS: + return "\u2029"; + default: + throw new ArgumentOutOfRangeException (); + } + } + } +} + diff --git a/ICSharpCode.Decompiler/FlowAnalysis/ControlFlowNode.cs b/ICSharpCode.Decompiler/FlowAnalysis/ControlFlowNode.cs index d600188ee..b33a90db5 100644 --- a/ICSharpCode.Decompiler/FlowAnalysis/ControlFlowNode.cs +++ b/ICSharpCode.Decompiler/FlowAnalysis/ControlFlowNode.cs @@ -121,34 +121,34 @@ namespace ICSharpCode.Decompiler.FlowAnalysis return false; } - public static GraphVizGraph ExportGraph(IReadOnlyList nodes, Func labelFunc = null) - { - if (labelFunc == null) { - labelFunc = node => { - var block = node.UserData as IL.Block; - return block != null ? block.Label : node.UserData?.ToString(); - }; - } - GraphVizGraph g = new GraphVizGraph(); - GraphVizNode[] n = new GraphVizNode[nodes.Count]; - for (int i = 0; i < n.Length; i++) { - n[i] = new GraphVizNode(nodes[i].UserIndex); - n[i].shape = "box"; - n[i].label = labelFunc(nodes[i]); - g.AddNode(n[i]); - } - foreach (var source in nodes) { - foreach (var target in source.Successors) { - g.AddEdge(new GraphVizEdge(source.UserIndex, target.UserIndex)); - } - if (source.ImmediateDominator != null) { - g.AddEdge( - new GraphVizEdge(source.ImmediateDominator.UserIndex, source.UserIndex) { - color = "green" - }); - } - } - return g; - } + //public static GraphVizGraph ExportGraph(IReadOnlyList nodes, Func labelFunc = null) + //{ + // if (labelFunc == null) { + // labelFunc = node => { + // var block = node.UserData as IL.Block; + // return block != null ? block.Label : node.UserData?.ToString(); + // }; + // } + // GraphVizGraph g = new GraphVizGraph(); + // GraphVizNode[] n = new GraphVizNode[nodes.Count]; + // for (int i = 0; i < n.Length; i++) { + // n[i] = new GraphVizNode(nodes[i].UserIndex); + // n[i].shape = "box"; + // n[i].label = labelFunc(nodes[i]); + // g.AddNode(n[i]); + // } + // foreach (var source in nodes) { + // foreach (var target in source.Successors) { + // g.AddEdge(new GraphVizEdge(source.UserIndex, target.UserIndex)); + // } + // if (source.ImmediateDominator != null) { + // g.AddEdge( + // new GraphVizEdge(source.ImmediateDominator.UserIndex, source.UserIndex) { + // color = "green" + // }); + // } + // } + // return g; + //} } } diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index bc801d645..5aba73328 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -144,7 +144,19 @@ + + + + + + + + + + + + @@ -175,6 +187,7 @@ + @@ -260,11 +273,30 @@ + + + + + + + + + + + + + + + + + + + @@ -340,17 +372,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -369,14 +554,6 @@ {D68133BD-1E63-496E-9EDE-4FBDBF77B486} Mono.Cecil - - {2B8F4F83-C2B3-4E84-A27B-8DEE1BE0E006} - ICSharpCode.NRefactory.Cecil - - - {3b2a5653-ec97-4001-bb9b-d90f1af2c371} - ICSharpCode.NRefactory - @@ -384,6 +561,16 @@ + + + CSharp\Ast\PatternMatching\Pattern Matching.html + + + + + Documentation\XML Documentation.html + + diff --git a/ICSharpCode.Decompiler/Semantics/AmbiguousResolveResult.cs b/ICSharpCode.Decompiler/Semantics/AmbiguousResolveResult.cs new file mode 100644 index 000000000..dec7ade3a --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/AmbiguousResolveResult.cs @@ -0,0 +1,51 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Represents an ambiguous type resolve result. + /// + public class AmbiguousTypeResolveResult : TypeResolveResult + { + public AmbiguousTypeResolveResult(IType type) : base(type) + { + } + + public override bool IsError { + get { return true; } + } + } + + /// + /// Represents an ambiguous field/property/event access. + /// + public class AmbiguousMemberResolveResult : MemberResolveResult + { + public AmbiguousMemberResolveResult(ResolveResult targetResult, IMember member) : base(targetResult, member) + { + } + + public override bool IsError { + get { return true; } + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/ArrayAccessResolveResult.cs b/ICSharpCode.Decompiler/Semantics/ArrayAccessResolveResult.cs new file mode 100644 index 000000000..e8acea445 --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/ArrayAccessResolveResult.cs @@ -0,0 +1,50 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; +using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Resolve result representing an array access. + /// + public class ArrayAccessResolveResult : ResolveResult + { + public readonly ResolveResult Array; + public readonly IList Indexes; + + public ArrayAccessResolveResult(IType elementType, ResolveResult array, IList indexes) : base(elementType) + { + if (array == null) + throw new ArgumentNullException("array"); + if (indexes == null) + throw new ArgumentNullException("indexes"); + this.Array = array; + this.Indexes = indexes; + } + + public override IEnumerable GetChildResults() + { + return new [] { Array }.Concat(Indexes); + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/ArrayCreateResolveResult.cs b/ICSharpCode.Decompiler/Semantics/ArrayCreateResolveResult.cs new file mode 100644 index 000000000..eb9dbd417 --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/ArrayCreateResolveResult.cs @@ -0,0 +1,60 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; +using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Resolve result representing an array creation. + /// + public class ArrayCreateResolveResult : ResolveResult + { + /// + /// Gets the size arguments. + /// + public readonly IList SizeArguments; + + /// + /// Gets the initializer elements. + /// This field may be null if no initializer was specified. + /// + public readonly IList InitializerElements; + + public ArrayCreateResolveResult(IType arrayType, IList sizeArguments, IList initializerElements) + : base(arrayType) + { + if (sizeArguments == null) + throw new ArgumentNullException("sizeArguments"); + this.SizeArguments = sizeArguments; + this.InitializerElements = initializerElements; + } + + public override IEnumerable GetChildResults() + { + if (InitializerElements != null) + return SizeArguments.Concat(InitializerElements); + else + return SizeArguments; + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/ByReferenceResolveResult.cs b/ICSharpCode.Decompiler/Semantics/ByReferenceResolveResult.cs new file mode 100644 index 000000000..50995312f --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/ByReferenceResolveResult.cs @@ -0,0 +1,66 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Globalization; +using System.Linq; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Represents the resolve result of an 'ref x' or 'out x' expression. + /// + public class ByReferenceResolveResult : ResolveResult + { + public bool IsOut { get; private set; } + public bool IsRef { get { return !IsOut;} } + + public readonly ResolveResult ElementResult; + + public ByReferenceResolveResult(ResolveResult elementResult, bool isOut) + : this(elementResult.Type, isOut) + { + this.ElementResult = elementResult; + } + + public ByReferenceResolveResult(IType elementType, bool isOut) + : base(new ByReferenceType(elementType)) + { + this.IsOut = isOut; + } + + public IType ElementType { + get { return ((ByReferenceType)this.Type).ElementType; } + } + + public override IEnumerable GetChildResults() + { + if (ElementResult != null) + return new[] { ElementResult }; + else + return Enumerable.Empty(); + } + + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "[{0} {1} {2}]", GetType().Name, IsOut ? "out" : "ref", ElementType); + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/ConstantResolveResult.cs b/ICSharpCode.Decompiler/Semantics/ConstantResolveResult.cs new file mode 100644 index 000000000..abce12597 --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/ConstantResolveResult.cs @@ -0,0 +1,55 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Globalization; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// ResolveResult representing a compile-time constant. + /// Note: this class is mainly used for literals; there may be other ResolveResult classes + /// which are compile-time constants as well. + /// For example, a reference to a const field results in a . + /// + /// Check to determine is a resolve result is a constant. + /// + public class ConstantResolveResult : ResolveResult + { + object constantValue; + + public ConstantResolveResult(IType type, object constantValue) : base(type) + { + this.constantValue = constantValue; + } + + public override bool IsCompileTimeConstant { + get { return true; } + } + + public override object ConstantValue { + get { return constantValue; } + } + + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "[{0} {1} = {2}]", GetType().Name, this.Type, constantValue); + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/Conversion.cs b/ICSharpCode.Decompiler/Semantics/Conversion.cs new file mode 100644 index 000000000..3dbfca1be --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/Conversion.cs @@ -0,0 +1,568 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Holds information about a conversion between two types. + /// + public abstract class Conversion : IEquatable + { + #region Conversion factory methods + /// + /// Not a valid conversion. + /// + public static readonly Conversion None = new InvalidConversion(); + + /// + /// Identity conversion. + /// + public static readonly Conversion IdentityConversion = new BuiltinConversion(true, 0); + + public static readonly Conversion ImplicitNumericConversion = new NumericOrEnumerationConversion(true, false); + public static readonly Conversion ExplicitNumericConversion = new NumericOrEnumerationConversion(false, false); + public static readonly Conversion ImplicitLiftedNumericConversion = new NumericOrEnumerationConversion(true, true); + public static readonly Conversion ExplicitLiftedNumericConversion = new NumericOrEnumerationConversion(false, true); + + public static Conversion EnumerationConversion(bool isImplicit, bool isLifted) + { + return new NumericOrEnumerationConversion(isImplicit, isLifted, true); + } + + public static readonly Conversion NullLiteralConversion = new BuiltinConversion(true, 1); + + /// + /// The numeric conversion of a constant expression. + /// + public static readonly Conversion ImplicitConstantExpressionConversion = new BuiltinConversion(true, 2); + + public static readonly Conversion ImplicitReferenceConversion = new BuiltinConversion(true, 3); + public static readonly Conversion ExplicitReferenceConversion = new BuiltinConversion(false, 3); + + public static readonly Conversion ImplicitDynamicConversion = new BuiltinConversion(true, 4); + public static readonly Conversion ExplicitDynamicConversion = new BuiltinConversion(false, 4); + + public static readonly Conversion ImplicitNullableConversion = new BuiltinConversion(true, 5); + public static readonly Conversion ExplicitNullableConversion = new BuiltinConversion(false, 5); + + public static readonly Conversion ImplicitPointerConversion = new BuiltinConversion(true, 6); + public static readonly Conversion ExplicitPointerConversion = new BuiltinConversion(false, 6); + + public static readonly Conversion BoxingConversion = new BuiltinConversion(true, 7); + public static readonly Conversion UnboxingConversion = new BuiltinConversion(false, 8); + + /// + /// C# 'as' cast. + /// + public static readonly Conversion TryCast = new BuiltinConversion(false, 9); + + [Obsolete("Use UserDefinedConversion() instead")] + public static Conversion UserDefinedImplicitConversion(IMethod operatorMethod, Conversion conversionBeforeUserDefinedOperator, Conversion conversionAfterUserDefinedOperator, bool isLifted) + { + if (operatorMethod == null) + throw new ArgumentNullException("operatorMethod"); + return new UserDefinedConv(true, operatorMethod, conversionBeforeUserDefinedOperator, conversionAfterUserDefinedOperator, isLifted, false); + } + + [Obsolete("Use UserDefinedConversion() instead")] + public static Conversion UserDefinedExplicitConversion(IMethod operatorMethod, Conversion conversionBeforeUserDefinedOperator, Conversion conversionAfterUserDefinedOperator, bool isLifted) + { + if (operatorMethod == null) + throw new ArgumentNullException("operatorMethod"); + return new UserDefinedConv(false, operatorMethod, conversionBeforeUserDefinedOperator, conversionAfterUserDefinedOperator, isLifted, false); + } + + public static Conversion UserDefinedConversion(IMethod operatorMethod, bool isImplicit, Conversion conversionBeforeUserDefinedOperator, Conversion conversionAfterUserDefinedOperator, bool isLifted = false, bool isAmbiguous = false) + { + if (operatorMethod == null) + throw new ArgumentNullException("operatorMethod"); + return new UserDefinedConv(isImplicit, operatorMethod, conversionBeforeUserDefinedOperator, conversionAfterUserDefinedOperator, isLifted, isAmbiguous); + } + + public static Conversion MethodGroupConversion(IMethod chosenMethod, bool isVirtualMethodLookup, bool delegateCapturesFirstArgument) + { + if (chosenMethod == null) + throw new ArgumentNullException("chosenMethod"); + return new MethodGroupConv(chosenMethod, isVirtualMethodLookup, delegateCapturesFirstArgument, isValid: true); + } + + public static Conversion InvalidMethodGroupConversion(IMethod chosenMethod, bool isVirtualMethodLookup, bool delegateCapturesFirstArgument) + { + if (chosenMethod == null) + throw new ArgumentNullException("chosenMethod"); + return new MethodGroupConv(chosenMethod, isVirtualMethodLookup, delegateCapturesFirstArgument, isValid: false); + } + #endregion + + #region Inner classes + sealed class InvalidConversion : Conversion + { + public override bool IsValid { + get { return false; } + } + + public override string ToString() + { + return "None"; + } + } + + sealed class NumericOrEnumerationConversion : Conversion + { + readonly bool isImplicit; + readonly bool isLifted; + readonly bool isEnumeration; + + public NumericOrEnumerationConversion(bool isImplicit, bool isLifted, bool isEnumeration = false) + { + this.isImplicit = isImplicit; + this.isLifted = isLifted; + this.isEnumeration = isEnumeration; + } + + public override bool IsImplicit { + get { return isImplicit; } + } + + public override bool IsExplicit { + get { return !isImplicit; } + } + + public override bool IsNumericConversion { + get { return !isEnumeration; } + } + + public override bool IsEnumerationConversion { + get { return isEnumeration; } + } + + public override bool IsLifted { + get { return isLifted; } + } + + public override string ToString() + { + return (isImplicit ? "implicit" : "explicit") + + (isLifted ? " lifted" : "") + + (isEnumeration ? " enumeration" : " numeric") + + " conversion"; + } + + public override bool Equals(Conversion other) + { + NumericOrEnumerationConversion o = other as NumericOrEnumerationConversion; + return o != null && isImplicit == o.isImplicit && isLifted == o.isLifted && isEnumeration == o.isEnumeration; + } + + public override int GetHashCode() + { + return (isImplicit ? 1 : 0) + (isLifted ? 2 : 0) + (isEnumeration ? 4 : 0); + } + } + + sealed class BuiltinConversion : Conversion + { + readonly bool isImplicit; + readonly byte type; + + public BuiltinConversion(bool isImplicit, byte type) + { + this.isImplicit = isImplicit; + this.type = type; + } + + public override bool IsImplicit { + get { return isImplicit; } + } + + public override bool IsExplicit { + get { return !isImplicit; } + } + + public override bool IsIdentityConversion { + 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; } + } + + public override bool IsDynamicConversion { + get { return type == 4; } + } + + public override bool IsNullableConversion { + get { return type == 5; } + } + + public override bool IsPointerConversion { + get { return type == 6; } + } + + public override bool IsBoxingConversion { + get { return type == 7; } + } + + public override bool IsUnboxingConversion { + get { return type == 8; } + } + + public override bool IsTryCast { + get { return type == 9; } + } + + public override string ToString() + { + string name = null; + switch (type) { + case 0: + return "identity conversion"; + case 1: + return "null-literal conversion"; + case 2: + name = "constant-expression"; + break; + case 3: + name = "reference"; + break; + case 4: + name = "dynamic"; + break; + case 5: + name = "nullable"; + break; + case 6: + name = "pointer"; + break; + case 7: + return "boxing conversion"; + case 8: + return "unboxing conversion"; + case 9: + return "try cast"; + } + return (isImplicit ? "implicit " : "explicit ") + name + " conversion"; + } + } + + sealed class UserDefinedConv : Conversion + { + readonly IMethod method; + readonly bool isLifted; + readonly Conversion conversionBeforeUserDefinedOperator; + readonly Conversion conversionAfterUserDefinedOperator; + readonly bool isImplicit; + readonly bool isValid; + + public UserDefinedConv(bool isImplicit, IMethod method, Conversion conversionBeforeUserDefinedOperator, Conversion conversionAfterUserDefinedOperator, bool isLifted, bool isAmbiguous) + { + this.method = method; + this.isLifted = isLifted; + this.conversionBeforeUserDefinedOperator = conversionBeforeUserDefinedOperator; + this.conversionAfterUserDefinedOperator = conversionAfterUserDefinedOperator; + this.isImplicit = isImplicit; + this.isValid = !isAmbiguous; + } + + public override bool IsValid { + get { return isValid; } + } + + public override bool IsImplicit { + get { return isImplicit; } + } + + public override bool IsExplicit { + get { return !isImplicit; } + } + + public override bool IsLifted { + get { return isLifted; } + } + + public override bool IsUserDefined { + get { return true; } + } + + public override Conversion ConversionBeforeUserDefinedOperator { + get { return conversionBeforeUserDefinedOperator; } + } + + public override Conversion ConversionAfterUserDefinedOperator { + get { return conversionAfterUserDefinedOperator; } + } + + public override IMethod Method { + get { return method; } + } + + public override bool Equals(Conversion other) + { + UserDefinedConv o = other as UserDefinedConv; + return o != null && isLifted == o.isLifted && isImplicit == o.isImplicit && isValid == o.isValid && method.Equals(o.method); + } + + public override int GetHashCode() + { + return unchecked(method.GetHashCode() + (isLifted ? 31 : 27) + (isImplicit ? 71 : 61) + (isValid ? 107 : 109)); + } + + public override string ToString() + { + return (isImplicit ? "implicit" : "explicit") + + (isLifted ? " lifted" : "") + + (isValid ? "" : " ambiguous") + + "user-defined conversion (" + method + ")"; + } + } + + sealed class MethodGroupConv : Conversion + { + readonly IMethod method; + readonly bool isVirtualMethodLookup; + readonly bool delegateCapturesFirstArgument; + readonly bool isValid; + + public MethodGroupConv(IMethod method, bool isVirtualMethodLookup, bool delegateCapturesFirstArgument, bool isValid) + { + this.method = method; + this.isVirtualMethodLookup = isVirtualMethodLookup; + this.delegateCapturesFirstArgument = delegateCapturesFirstArgument; + this.isValid = isValid; + } + + public override bool IsValid { + get { return isValid; } + } + + public override bool IsImplicit { + get { return true; } + } + + public override bool IsMethodGroupConversion { + get { return true; } + } + + public override bool IsVirtualMethodLookup { + get { return isVirtualMethodLookup; } + } + + public override bool DelegateCapturesFirstArgument { + get { return delegateCapturesFirstArgument; } + } + + public override IMethod Method { + get { return method; } + } + + public override bool Equals(Conversion other) + { + MethodGroupConv o = other as MethodGroupConv; + return o != null && method.Equals(o.method); + } + + public override int GetHashCode() + { + return method.GetHashCode(); + } + } + #endregion + + /// + /// Gets whether the conversion is valid. + /// + public virtual bool IsValid { + get { return true; } + } + + public virtual bool IsImplicit { + get { return false; } + } + + public virtual bool IsExplicit { + get { return false; } + } + + /// + /// Gets whether the conversion is an 'as' cast. + /// + public virtual bool IsTryCast { + get { return false; } + } + + public virtual bool IsIdentityConversion { + get { return false; } + } + + public virtual bool IsNullLiteralConversion { + get { return false; } + } + + public virtual bool IsConstantExpressionConversion { + get { return false; } + } + + public virtual bool IsNumericConversion { + get { return false; } + } + + /// + /// Gets whether this conversion is a lifted version of another conversion. + /// + public virtual bool IsLifted { + get { return false; } + } + + /// + /// Gets whether the conversion is dynamic. + /// + public virtual bool IsDynamicConversion { + get { return false; } + } + + /// + /// Gets whether the conversion is a reference conversion. + /// + public virtual bool IsReferenceConversion { + get { return false; } + } + + /// + /// Gets whether the conversion is an enumeration conversion. + /// + public virtual bool IsEnumerationConversion { + get { return false; } + } + + /// + /// Gets whether the conversion is a nullable conversion + /// (conversion between a nullable type and the regular type). + /// + public virtual bool IsNullableConversion { + get { return false; } + } + + /// + /// Gets whether this conversion is user-defined (op_Implicit or op_Explicit). + /// + public virtual bool IsUserDefined { + get { return false; } + } + + /// + /// The conversion that is applied to the input before the user-defined conversion operator is invoked. + /// + public virtual Conversion ConversionBeforeUserDefinedOperator { + get { return null; } + } + + /// + /// The conversion that is applied to the result of the user-defined conversion operator. + /// + public virtual Conversion ConversionAfterUserDefinedOperator { + get { return null; } + } + + /// + /// Gets whether this conversion is a boxing conversion. + /// + public virtual bool IsBoxingConversion { + get { return false; } + } + + /// + /// Gets whether this conversion is an unboxing conversion. + /// + public virtual bool IsUnboxingConversion { + get { return false; } + } + + /// + /// Gets whether this conversion is a pointer conversion. + /// + public virtual bool IsPointerConversion { + get { return false; } + } + + /// + /// Gets whether this conversion is a method group conversion. + /// + public virtual bool IsMethodGroupConversion { + get { return false; } + } + + /// + /// For method-group conversions, gets whether to perform a virtual method lookup at runtime. + /// + public virtual bool IsVirtualMethodLookup { + get { return false; } + } + + /// + /// For method-group conversions, gets whether the conversion captures the first argument. + /// + /// For instance methods, this property always returns true for C# method-group conversions. + /// For static methods, this property returns true for method-group conversions of an extension method performed on an instance (eg. Func<int> f = myEnumerable.Single). + /// + public virtual bool DelegateCapturesFirstArgument { + get { return false; } + } + + /// + /// Gets whether this conversion is an anonymous function conversion. + /// + public virtual bool IsAnonymousFunctionConversion { + get { return false; } + } + + /// + /// Gets the method associated with this conversion. + /// For user-defined conversions, this is the method being called. + /// For method-group conversions, this is the method that was chosen from the group. + /// + public virtual IMethod Method { + get { return null; } + } + + public override sealed bool Equals(object obj) + { + return Equals(obj as Conversion); + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public virtual bool Equals(Conversion other) + { + return this == other; + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/ConversionResolveResult.cs b/ICSharpCode.Decompiler/Semantics/ConversionResolveResult.cs new file mode 100644 index 000000000..8ae2f5437 --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/ConversionResolveResult.cs @@ -0,0 +1,68 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Represents an implicit or explicit type conversion. + /// conversionResolveResult.Input.Type is the source type; + /// conversionResolveResult.Type is the target type. + /// The property provides details about the kind of conversion. + /// + public class ConversionResolveResult : ResolveResult + { + public readonly ResolveResult Input; + public readonly Conversion Conversion; + + /// + /// For numeric conversions, specifies whether overflow checking is enabled. + /// + public readonly bool CheckForOverflow; + + public ConversionResolveResult(IType targetType, ResolveResult input, Conversion conversion) + : base(targetType) + { + if (input == null) + throw new ArgumentNullException("input"); + if (conversion == null) + throw new ArgumentNullException("conversion"); + this.Input = input; + this.Conversion = conversion; + } + + public ConversionResolveResult(IType targetType, ResolveResult input, Conversion conversion, bool checkForOverflow) + : this(targetType, input, conversion) + { + this.CheckForOverflow = checkForOverflow; + } + + public override bool IsError { + get { return !Conversion.IsValid; } + } + + public override IEnumerable GetChildResults() + { + return new [] { Input }; + } + + } +} diff --git a/ICSharpCode.Decompiler/Semantics/ErrorResolveResult.cs b/ICSharpCode.Decompiler/Semantics/ErrorResolveResult.cs new file mode 100644 index 000000000..569e7244c --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/ErrorResolveResult.cs @@ -0,0 +1,56 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Represents a resolve error. + /// + /// Note: some errors are represented by other classes; for example a may + /// be erroneous if the conversion is invalid. + /// + /// . + public class ErrorResolveResult : ResolveResult + { + /// + /// Gets an ErrorResolveResult instance with Type = SpecialType.UnknownType. + /// + public static readonly ErrorResolveResult UnknownError = new ErrorResolveResult(SpecialType.UnknownType); + + public ErrorResolveResult(IType type) : base(type) + { + } + + public ErrorResolveResult(IType type, string message, TextLocation location) : base(type) + { + this.Message = message; + this.Location = location; + } + + public override bool IsError { + get { return true; } + } + + public string Message { get; private set; } + + public TextLocation Location { get; private set; } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/ForEachResolveResult.cs b/ICSharpCode.Decompiler/Semantics/ForEachResolveResult.cs new file mode 100644 index 000000000..5ed44bf60 --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/ForEachResolveResult.cs @@ -0,0 +1,90 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Resolve result representing a 'foreach' loop. + /// + public class ForEachResolveResult : ResolveResult + { + /// + /// Gets the semantic tree for the call to GetEnumerator. + /// + public readonly ResolveResult GetEnumeratorCall; + + /// + /// Gets the collection type. + /// + public readonly IType CollectionType; + + /// + /// Gets the enumerator type. + /// + public readonly IType EnumeratorType; + + /// + /// Gets the element type. + /// This is the type that would be inferred for an implicitly-typed element variable. + /// For explicitly-typed element variables, this type may differ from ElementVariable.Type. + /// + public readonly IType ElementType; + + /// + /// Gets the element variable. + /// + public readonly IVariable ElementVariable; + + /// + /// Gets the Current property on the IEnumerator. + /// Returns null if the property is not found. + /// + public readonly IProperty CurrentProperty; + + /// + /// Gets the MoveNext() method on the IEnumerator. + /// Returns null if the method is not found. + /// + public readonly IMethod MoveNextMethod; + + public ForEachResolveResult(ResolveResult getEnumeratorCall, IType collectionType, IType enumeratorType, IType elementType, IVariable elementVariable, IProperty currentProperty, IMethod moveNextMethod, IType voidType) + : base(voidType) + { + if (getEnumeratorCall == null) + throw new ArgumentNullException("getEnumeratorCall"); + if (collectionType == null) + throw new ArgumentNullException("collectionType"); + if (enumeratorType == null) + throw new ArgumentNullException("enumeratorType"); + if (elementType == null) + throw new ArgumentNullException("elementType"); + if (elementVariable == null) + throw new ArgumentNullException("elementVariable"); + this.GetEnumeratorCall = getEnumeratorCall; + this.CollectionType = collectionType; + this.EnumeratorType = enumeratorType; + this.ElementType = elementType; + this.ElementVariable = elementVariable; + this.CurrentProperty = currentProperty; + this.MoveNextMethod = moveNextMethod; + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/InitializedObjectResolveResult.cs b/ICSharpCode.Decompiler/Semantics/InitializedObjectResolveResult.cs new file mode 100644 index 000000000..1eed13396 --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/InitializedObjectResolveResult.cs @@ -0,0 +1,34 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Refers to the object that is currently being initialized. + /// Used within . + /// + public class InitializedObjectResolveResult : ResolveResult + { + public InitializedObjectResolveResult(IType type) : base(type) + { + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/InvocationResolveResult.cs b/ICSharpCode.Decompiler/Semantics/InvocationResolveResult.cs new file mode 100644 index 000000000..b5d2a4d94 --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/InvocationResolveResult.cs @@ -0,0 +1,75 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; + +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Represents the result of a method, constructor or indexer invocation. + /// + public class InvocationResolveResult : MemberResolveResult + { + /// + /// Gets the arguments that are being passed to the method, in the order the arguments are being evaluated. + /// + public readonly IList Arguments; + + /// + /// 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 is used + /// to refer to the result of this invocation. + /// + public readonly IList InitializerStatements; + + public InvocationResolveResult(ResolveResult targetResult, IParameterizedMember member, + IList arguments = null, + IList initializerStatements = null, + IType returnTypeOverride = null) + : base(targetResult, member, returnTypeOverride) + { + this.Arguments = arguments ?? EmptyList.Instance; + this.InitializerStatements = initializerStatements ?? EmptyList.Instance; + } + + public new IParameterizedMember Member { + get { return (IParameterizedMember)base.Member; } + } + + /// + /// Gets the arguments in the order they are being passed to the method. + /// For parameter arrays (params), this will return an ArrayCreateResolveResult. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", + Justification = "Derived methods may be expensive and create new lists")] + public virtual IList GetArgumentsForCall() + { + return Arguments; + } + + public override IEnumerable GetChildResults() + { + return base.GetChildResults().Concat(this.Arguments).Concat(this.InitializerStatements); + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/LocalResolveResult.cs b/ICSharpCode.Decompiler/Semantics/LocalResolveResult.cs new file mode 100644 index 000000000..fddf6a04b --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/LocalResolveResult.cs @@ -0,0 +1,77 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Globalization; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Represents a local variable or parameter. + /// + public class LocalResolveResult : ResolveResult + { + readonly IVariable variable; + + public LocalResolveResult(IVariable variable) + : base(UnpackTypeIfByRefParameter(variable)) + { + this.variable = variable; + } + + static IType UnpackTypeIfByRefParameter(IVariable variable) + { + if (variable == null) + throw new ArgumentNullException("variable"); + IType type = variable.Type; + if (type.Kind == TypeKind.ByReference) { + IParameter p = variable as IParameter; + if (p != null && (p.IsRef || p.IsOut)) + return ((ByReferenceType)type).ElementType; + } + return type; + } + + public IVariable Variable { + get { return variable; } + } + + public bool IsParameter { + get { return variable is IParameter; } + } + + public override bool IsCompileTimeConstant { + get { return variable.IsConst; } + } + + public override object ConstantValue { + get { return IsParameter ? null : variable.ConstantValue; } + } + + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "[LocalResolveResult {0}]", variable); + } + + public override DomRegion GetDefinitionRegion() + { + return variable.Region; + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/MemberResolveResult.cs b/ICSharpCode.Decompiler/Semantics/MemberResolveResult.cs new file mode 100644 index 000000000..553b721e3 --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/MemberResolveResult.cs @@ -0,0 +1,148 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Globalization; +using System.Linq; + +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Represents the result of a member invocation. + /// Used for field/property/event access. + /// Also, derives from MemberResolveResult. + /// + public class MemberResolveResult : ResolveResult + { + readonly IMember member; + readonly bool isConstant; + readonly object constantValue; + readonly ResolveResult targetResult; + readonly bool isVirtualCall; + + public MemberResolveResult(ResolveResult targetResult, IMember member, IType returnTypeOverride = null) + : base(returnTypeOverride ?? ComputeType(member)) + { + this.targetResult = targetResult; + this.member = member; + var thisRR = targetResult as ThisResolveResult; + this.isVirtualCall = member.IsOverridable && !(thisRR != null && thisRR.CausesNonVirtualInvocation); + + IField field = member as IField; + if (field != null) { + isConstant = field.IsConst; + if (isConstant) + constantValue = field.ConstantValue; + } + } + + public MemberResolveResult(ResolveResult targetResult, IMember member, bool isVirtualCall, IType returnTypeOverride = null) + : base(returnTypeOverride ?? ComputeType(member)) + { + this.targetResult = targetResult; + this.member = member; + this.isVirtualCall = isVirtualCall; + IField field = member as IField; + if (field != null) { + isConstant = field.IsConst; + if (isConstant) + constantValue = field.ConstantValue; + } + } + + static IType ComputeType(IMember member) + { + switch (member.SymbolKind) { + case SymbolKind.Constructor: + return member.DeclaringType ?? SpecialType.UnknownType; + case SymbolKind.Field: + if (((IField)member).IsFixed) + return new PointerType(member.ReturnType); + break; + } + return member.ReturnType; + } + + public MemberResolveResult(ResolveResult targetResult, IMember member, IType returnType, bool isConstant, object constantValue) + : base(returnType) + { + this.targetResult = targetResult; + this.member = member; + this.isConstant = isConstant; + this.constantValue = constantValue; + } + + public MemberResolveResult(ResolveResult targetResult, IMember member, IType returnType, bool isConstant, object constantValue, bool isVirtualCall) + : base(returnType) + { + this.targetResult = targetResult; + this.member = member; + this.isConstant = isConstant; + this.constantValue = constantValue; + this.isVirtualCall = isVirtualCall; + } + + public ResolveResult TargetResult { + get { return targetResult; } + } + + /// + /// Gets the member. + /// This property never returns null. + /// + public IMember Member { + get { return member; } + } + + /// + /// Gets whether this MemberResolveResult is a virtual call. + /// + public bool IsVirtualCall { + get { return isVirtualCall; } + } + + public override bool IsCompileTimeConstant { + get { return isConstant; } + } + + public override object ConstantValue { + get { return constantValue; } + } + + public override IEnumerable GetChildResults() + { + if (targetResult != null) + return new[] { targetResult }; + else + return Enumerable.Empty(); + } + + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "[{0} {1}]", GetType().Name, member); + } + + public override DomRegion GetDefinitionRegion() + { + return member.Region; + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/NamedArgumentResolveResult.cs b/ICSharpCode.Decompiler/Semantics/NamedArgumentResolveResult.cs new file mode 100644 index 000000000..522ef7cc2 --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/NamedArgumentResolveResult.cs @@ -0,0 +1,81 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Represents a named argument. + /// + public class NamedArgumentResolveResult : ResolveResult + { + /// + /// Gets the member to which the parameter belongs. + /// This field can be null. + /// + public readonly IParameterizedMember Member; + + /// + /// Gets the parameter. + /// This field can be null. + /// + public readonly IParameter Parameter; + + /// + /// Gets the parameter name. + /// + public readonly string ParameterName; + + /// + /// Gets the argument passed to the parameter. + /// + public readonly ResolveResult Argument; + + public NamedArgumentResolveResult(IParameter parameter, ResolveResult argument, IParameterizedMember member = null) + : base(argument.Type) + { + if (parameter == null) + throw new ArgumentNullException("parameter"); + if (argument == null) + throw new ArgumentNullException("argument"); + this.Member = member; + this.Parameter = parameter; + this.ParameterName = parameter.Name; + this.Argument = argument; + } + + public NamedArgumentResolveResult(string parameterName, ResolveResult argument) + : base(argument.Type) + { + if (parameterName == null) + throw new ArgumentNullException("parameterName"); + if (argument == null) + throw new ArgumentNullException("argument"); + this.ParameterName = parameterName; + this.Argument = argument; + } + + public override IEnumerable GetChildResults() + { + return new [] { Argument }; + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/NamespaceResolveResult.cs b/ICSharpCode.Decompiler/Semantics/NamespaceResolveResult.cs new file mode 100644 index 000000000..62fcbf4b1 --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/NamespaceResolveResult.cs @@ -0,0 +1,50 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Globalization; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Represents that an expression resolved to a namespace. + /// + public class NamespaceResolveResult : ResolveResult + { + readonly INamespace ns; + + public NamespaceResolveResult(INamespace ns) : base(SpecialType.UnknownType) + { + this.ns = ns; + } + + public INamespace Namespace { + get { return ns; } + } + + public string NamespaceName { + get { return ns.FullName; } + } + + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "[{0} {1}]", GetType().Name, ns); + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/OperatorResolveResult.cs b/ICSharpCode.Decompiler/Semantics/OperatorResolveResult.cs new file mode 100644 index 000000000..9f77b39b6 --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/OperatorResolveResult.cs @@ -0,0 +1,90 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq.Expressions; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Represents a unary/binary/ternary operator invocation. + /// + public class OperatorResolveResult : ResolveResult + { + readonly ExpressionType operatorType; + readonly IMethod userDefinedOperatorMethod; + readonly IList operands; + readonly bool isLiftedOperator; + + public OperatorResolveResult(IType resultType, ExpressionType operatorType, params ResolveResult[] operands) + : base(resultType) + { + if (operands == null) + throw new ArgumentNullException("operands"); + this.operatorType = operatorType; + this.operands = operands; + } + + public OperatorResolveResult(IType resultType, ExpressionType operatorType, IMethod userDefinedOperatorMethod, bool isLiftedOperator, IList operands) + : base(resultType) + { + if (operands == null) + throw new ArgumentNullException("operands"); + this.operatorType = operatorType; + this.userDefinedOperatorMethod = userDefinedOperatorMethod; + this.isLiftedOperator = isLiftedOperator; + this.operands = operands; + } + + /// + /// Gets the operator type. + /// + public ExpressionType OperatorType { + get { return operatorType; } + } + + /// + /// Gets the operands. + /// + public IList Operands { + get { return operands; } + } + + /// + /// Gets the user defined operator method. + /// Returns null if this is a predefined operator. + /// + public IMethod UserDefinedOperatorMethod { + get { return userDefinedOperatorMethod; } + } + + /// + /// Gets whether this is a lifted operator. + /// + public bool IsLiftedOperator { + get { return isLiftedOperator; } + } + + public override IEnumerable GetChildResults() + { + return operands; + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/ResolveResult.cs b/ICSharpCode.Decompiler/Semantics/ResolveResult.cs new file mode 100644 index 000000000..3fce91236 --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/ResolveResult.cs @@ -0,0 +1,78 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Represents the result of resolving an expression. + /// + public class ResolveResult + { + readonly IType type; + + public ResolveResult(IType type) + { + if (type == null) + throw new ArgumentNullException("type"); + this.type = type; + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", + Justification = "Unrelated to object.GetType()")] + public IType Type { + get { return type; } + } + + public virtual bool IsCompileTimeConstant { + get { return false; } + } + + public virtual object ConstantValue { + get { return null; } + } + + public virtual bool IsError { + get { return false; } + } + + public override string ToString() + { + return "[" + GetType().Name + " " + type + "]"; + } + + public virtual IEnumerable GetChildResults() + { + return Enumerable.Empty(); + } + + public virtual DomRegion GetDefinitionRegion() + { + return DomRegion.Empty; + } + + public virtual ResolveResult ShallowClone() + { + return (ResolveResult)MemberwiseClone(); + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/SizeOfResolveResult.cs b/ICSharpCode.Decompiler/Semantics/SizeOfResolveResult.cs new file mode 100644 index 000000000..41ad3be7d --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/SizeOfResolveResult.cs @@ -0,0 +1,66 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Represents the 'sizeof'. + /// + public class SizeOfResolveResult : ResolveResult + { + readonly IType referencedType; + readonly int? constantValue; + + public SizeOfResolveResult(IType int32, IType referencedType, int? constantValue) + : base(int32) + { + if (referencedType == null) + throw new ArgumentNullException("referencedType"); + this.referencedType = referencedType; + this.constantValue = constantValue; + } + + /// + /// The type referenced by the 'sizeof'. + /// + public IType ReferencedType { + get { return referencedType; } + } + + public override bool IsCompileTimeConstant { + get { + return constantValue != null; + } + } + + public override object ConstantValue { + get { + return constantValue; + } + } + + public override bool IsError { + get { + return referencedType.IsReferenceType != false; + } + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/ThisResolveResult.cs b/ICSharpCode.Decompiler/Semantics/ThisResolveResult.cs new file mode 100644 index 000000000..302ee4ed2 --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/ThisResolveResult.cs @@ -0,0 +1,44 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Represents the 'this' reference. + /// Also used for the 'base' reference. + /// + public class ThisResolveResult : ResolveResult + { + bool causesNonVirtualInvocation; + + public ThisResolveResult(IType type, bool causesNonVirtualInvocation = false) : base(type) + { + this.causesNonVirtualInvocation = causesNonVirtualInvocation; + } + + /// + /// Gets whether this resolve result causes member invocations to be non-virtual. + /// + public bool CausesNonVirtualInvocation { + get { return causesNonVirtualInvocation; } + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/TypeIsResolveResult.cs b/ICSharpCode.Decompiler/Semantics/TypeIsResolveResult.cs new file mode 100644 index 000000000..1704eafff --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/TypeIsResolveResult.cs @@ -0,0 +1,47 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Resolve result for a C# 'is' expression. + /// "Input is TargetType". + /// + public class TypeIsResolveResult : ResolveResult + { + public readonly ResolveResult Input; + /// + /// Type that is being compared with. + /// + public readonly IType TargetType; + + public TypeIsResolveResult(ResolveResult input, IType targetType, IType booleanType) + : base(booleanType) + { + if (input == null) + throw new ArgumentNullException("input"); + if (targetType == null) + throw new ArgumentNullException("targetType"); + this.Input = input; + this.TargetType = targetType; + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/TypeOfResolveResult.cs b/ICSharpCode.Decompiler/Semantics/TypeOfResolveResult.cs new file mode 100644 index 000000000..b88b24719 --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/TypeOfResolveResult.cs @@ -0,0 +1,46 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Represents the 'typeof'. + /// + public class TypeOfResolveResult : ResolveResult + { + readonly IType referencedType; + + public TypeOfResolveResult(IType systemType, IType referencedType) + : base(systemType) + { + if (referencedType == null) + throw new ArgumentNullException("referencedType"); + this.referencedType = referencedType; + } + + /// + /// The type referenced by the 'typeof'. + /// + public IType ReferencedType { + get { return referencedType; } + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/TypeResolveResult.cs b/ICSharpCode.Decompiler/Semantics/TypeResolveResult.cs new file mode 100644 index 000000000..268865504 --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/TypeResolveResult.cs @@ -0,0 +1,47 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// The resolved expression refers to a type name. + /// + public class TypeResolveResult : ResolveResult + { + public TypeResolveResult(IType type) + : base(type) + { + } + + public override bool IsError { + get { return this.Type.Kind == TypeKind.Unknown; } + } + + public override DomRegion GetDefinitionRegion() + { + ITypeDefinition def = this.Type.GetDefinition(); + if (def != null) + return def.Region; + else + return DomRegion.Empty; + } + } +} diff --git a/ICSharpCode.Decompiler/Semantics/UnknownMemberResolveResult.cs b/ICSharpCode.Decompiler/Semantics/UnknownMemberResolveResult.cs new file mode 100644 index 000000000..1051bb961 --- /dev/null +++ b/ICSharpCode.Decompiler/Semantics/UnknownMemberResolveResult.cs @@ -0,0 +1,122 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Collections.ObjectModel; +using System.Globalization; +using System.Linq; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Represents an unknown member. + /// + public class UnknownMemberResolveResult : ResolveResult + { + readonly IType targetType; + readonly string memberName; + readonly ReadOnlyCollection typeArguments; + + public UnknownMemberResolveResult(IType targetType, string memberName, IEnumerable typeArguments) + : base(SpecialType.UnknownType) + { + if (targetType == null) + throw new ArgumentNullException("targetType"); + this.targetType = targetType; + this.memberName = memberName; + this.typeArguments = new ReadOnlyCollection(typeArguments.ToArray()); + } + + /// + /// The type on which the method is being called. + /// + public IType TargetType { + get { return targetType; } + } + + public string MemberName { + get { return memberName; } + } + + public ReadOnlyCollection TypeArguments { + get { return typeArguments; } + } + + public override bool IsError { + get { return true; } + } + + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "[{0} {1}.{2}]", GetType().Name, targetType, memberName); + } + } + + /// + /// Represents an unknown method. + /// + public class UnknownMethodResolveResult : UnknownMemberResolveResult + { + readonly ReadOnlyCollection parameters; + + public UnknownMethodResolveResult(IType targetType, string methodName, IEnumerable typeArguments, IEnumerable parameters) + : base(targetType, methodName, typeArguments) + { + this.parameters = new ReadOnlyCollection(parameters.ToArray()); + } + + public ReadOnlyCollection Parameters { + get { return parameters; } + } + } + + /// + /// Represents an unknown identifier. + /// + public class UnknownIdentifierResolveResult : ResolveResult + { + readonly string identifier; + readonly int typeArgumentCount; + + public UnknownIdentifierResolveResult(string identifier, int typeArgumentCount = 0) + : base(SpecialType.UnknownType) + { + this.identifier = identifier; + this.typeArgumentCount = typeArgumentCount; + } + + public string Identifier { + get { return identifier; } + } + + public int TypeArgumentCount { + get { return typeArgumentCount; } + } + + public override bool IsError { + get { return true; } + } + + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "[{0} {1}]", GetType().Name, identifier); + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index 772543e83..00809a304 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -113,10 +113,6 @@ {d68133bd-1e63-496e-9ede-4fbdbf77b486} Mono.Cecil - - {3b2a5653-ec97-4001-bb9b-d90f1af2c371} - ICSharpCode.NRefactory - {984cc812-9470-4a13-aff9-cc44068d666c} ICSharpCode.Decompiler diff --git a/ICSharpCode.Decompiler/TypeSystem/Accessibility.cs b/ICSharpCode.Decompiler/TypeSystem/Accessibility.cs new file mode 100644 index 000000000..9e633f7c7 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Accessibility.cs @@ -0,0 +1,117 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Enum that describes the accessibility of an entity. + /// + public enum Accessibility : byte + { + // note: some code depends on the fact that these values are within the range 0-7 + + /// + /// The entity is completely inaccessible. This is used for C# explicit interface implementations. + /// + None, + /// + /// The entity is only accessible within the same class. + /// + Private, + /// + /// The entity is accessible everywhere. + /// + Public, + /// + /// The entity is only accessible within the same class and in derived classes. + /// + Protected, + /// + /// The entity is accessible within the same project content. + /// + Internal, + /// + /// The entity is accessible both everywhere in the project content, and in all derived classes. + /// + /// This corresponds to C# 'protected internal'. + ProtectedOrInternal, + /// + /// The entity is accessible in derived classes within the same project content. + /// + /// C# does not support this accessibility. + ProtectedAndInternal, + } + + public interface IHasAccessibility + { + /// + /// Gets the accessibility of this entity. + /// + Accessibility Accessibility { get; } + + /// + /// Gets a value indicating whether this instance is private. + /// + /// + /// true if this instance is private; otherwise, false. + /// + bool IsPrivate { get; } + + /// + /// Gets a value indicating whether this instance is public. + /// + /// + /// true if this instance is public; otherwise, false. + /// + bool IsPublic { get; } + + /// + /// Gets a value indicating whether this instance is protected. + /// + /// + /// true if this instance is protected; otherwise, false. + /// + bool IsProtected { get; } + + /// + /// Gets a value indicating whether this instance is internal. + /// + /// + /// true if this instance is internal; otherwise, false. + /// + bool IsInternal { get; } + + /// + /// Gets a value indicating whether this instance is protected or internal. + /// + /// + /// true if this instance is protected or internal; otherwise, false. + /// + bool IsProtectedOrInternal { get; } + + /// + /// Gets a value indicating whether this instance is protected and internal. + /// + /// + /// true if this instance is protected and internal; otherwise, false. + /// + bool IsProtectedAndInternal { get; } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/AnonymousType.cs b/ICSharpCode.Decompiler/TypeSystem/AnonymousType.cs new file mode 100644 index 000000000..1c97be5eb --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/AnonymousType.cs @@ -0,0 +1,221 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; +using ICSharpCode.NRefactory.TypeSystem.Implementation; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Anonymous type. + /// + public class AnonymousType : AbstractType + { + ICompilation compilation; + IUnresolvedProperty[] unresolvedProperties; + IList resolvedProperties; + + public AnonymousType(ICompilation compilation, IList properties) + { + if (compilation == null) + throw new ArgumentNullException("compilation"); + if (properties == null) + throw new ArgumentNullException("properties"); + this.compilation = compilation; + this.unresolvedProperties = properties.ToArray(); + var context = new SimpleTypeResolveContext(compilation.MainAssembly); + this.resolvedProperties = new ProjectedList(context, unresolvedProperties, (c, p) => new AnonymousTypeProperty(p, c, this)); + } + + sealed class AnonymousTypeProperty : DefaultResolvedProperty + { + readonly AnonymousType declaringType; + + public AnonymousTypeProperty(IUnresolvedProperty unresolved, ITypeResolveContext parentContext, AnonymousType declaringType) + : base(unresolved, parentContext) + { + this.declaringType = declaringType; + } + + public override IType DeclaringType { + get { return declaringType; } + } + + public override bool Equals(object obj) + { + AnonymousTypeProperty p = obj as AnonymousTypeProperty; + return p != null && this.Name == p.Name && declaringType.Equals(p.declaringType); + } + + public override int GetHashCode() + { + return declaringType.GetHashCode() ^ unchecked(27 * this.Name.GetHashCode()); + } + + protected override IMethod CreateResolvedAccessor(IUnresolvedMethod unresolvedAccessor) + { + return new AnonymousTypeAccessor(unresolvedAccessor, context, this); + } + } + + sealed class AnonymousTypeAccessor : DefaultResolvedMethod + { + readonly AnonymousTypeProperty owner; + + public AnonymousTypeAccessor(IUnresolvedMethod unresolved, ITypeResolveContext parentContext, AnonymousTypeProperty owner) + : base(unresolved, parentContext, isExtensionMethod: false) + { + this.owner = owner; + } + + public override IMember AccessorOwner { + get { return owner; } + } + + public override IType DeclaringType { + get { return owner.DeclaringType; } + } + + public override bool Equals(object obj) + { + AnonymousTypeAccessor p = obj as AnonymousTypeAccessor; + return p != null && this.Name == p.Name && owner.DeclaringType.Equals(p.owner.DeclaringType); + } + + public override int GetHashCode() + { + return owner.DeclaringType.GetHashCode() ^ unchecked(27 * this.Name.GetHashCode()); + } + } + + public override ITypeReference ToTypeReference() + { + return new AnonymousTypeReference(unresolvedProperties); + } + + public override string Name { + get { return "Anonymous Type"; } + } + + public override TypeKind Kind { + get { return TypeKind.Anonymous; } + } + + public override IEnumerable DirectBaseTypes { + get { + yield return compilation.FindType(KnownTypeCode.Object); + } + } + + public override bool? IsReferenceType { + get { return true; } + } + + public IList Properties { + get { return resolvedProperties; } + } + + public override IEnumerable GetMethods(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) + return EmptyList.Instance; + else + return compilation.FindType(KnownTypeCode.Object).GetMethods(filter, options); + } + + public override IEnumerable GetMethods(IList typeArguments, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) + return EmptyList.Instance; + else + return compilation.FindType(KnownTypeCode.Object).GetMethods(typeArguments, filter, options); + } + + public override IEnumerable GetProperties(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + for (int i = 0; i < unresolvedProperties.Length; i++) { + if (filter == null || filter(unresolvedProperties[i])) + yield return resolvedProperties[i]; + } + } + + public override IEnumerable GetAccessors(Predicate filter, GetMemberOptions options) + { + for (int i = 0; i < unresolvedProperties.Length; i++) { + if (unresolvedProperties[i].CanGet) { + if (filter == null || filter(unresolvedProperties[i].Getter)) + yield return resolvedProperties[i].Getter; + } + if (unresolvedProperties[i].CanSet) { + if (filter == null || filter(unresolvedProperties[i].Setter)) + yield return resolvedProperties[i].Setter; + } + } + } + + public override int GetHashCode() + { + unchecked { + int hashCode = resolvedProperties.Count; + foreach (var p in resolvedProperties) { + hashCode *= 31; + hashCode += p.Name.GetHashCode() ^ p.ReturnType.GetHashCode(); + } + return hashCode; + } + } + + public override bool Equals(IType other) + { + AnonymousType o = other as AnonymousType; + if (o == null || resolvedProperties.Count != o.resolvedProperties.Count) + return false; + for (int i = 0; i < resolvedProperties.Count; i++) { + IProperty p1 = resolvedProperties[i]; + IProperty p2 = o.resolvedProperties[i]; + if (p1.Name != p2.Name || !p1.ReturnType.Equals(p2.ReturnType)) + return false; + } + return true; + } + } + + /// + /// Anonymous type reference. + /// + [Serializable] + public class AnonymousTypeReference : ITypeReference + { + readonly IUnresolvedProperty[] unresolvedProperties; + + public AnonymousTypeReference(IUnresolvedProperty[] properties) + { + if (properties == null) + throw new ArgumentNullException("properties"); + this.unresolvedProperties = properties; + } + + public IType Resolve(ITypeResolveContext context) + { + return new AnonymousType(context.Compilation, unresolvedProperties); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/ArrayType.cs b/ICSharpCode.Decompiler/TypeSystem/ArrayType.cs new file mode 100644 index 000000000..7d02785ee --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/ArrayType.cs @@ -0,0 +1,200 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Implementation; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Represents an array type. + /// + public sealed class ArrayType : TypeWithElementType, ICompilationProvider + { + readonly int dimensions; + readonly ICompilation compilation; + + public ArrayType(ICompilation compilation, IType elementType, int dimensions = 1) : base(elementType) + { + if (compilation == null) + throw new ArgumentNullException("compilation"); + if (dimensions <= 0) + throw new ArgumentOutOfRangeException("dimensions", dimensions, "dimensions must be positive"); + this.compilation = compilation; + this.dimensions = dimensions; + + ICompilationProvider p = elementType as ICompilationProvider; + if (p != null && p.Compilation != compilation) + throw new InvalidOperationException("Cannot create an array type using a different compilation from the element type."); + } + + public override TypeKind Kind { + get { return TypeKind.Array; } + } + + public ICompilation Compilation { + get { return compilation; } + } + + public int Dimensions { + get { return dimensions; } + } + + public override string NameSuffix { + get { + return "[" + new string(',', dimensions-1) + "]"; + } + } + + public override bool? IsReferenceType { + get { return true; } + } + + public override int GetHashCode() + { + return unchecked(elementType.GetHashCode() * 71681 + dimensions); + } + + public override bool Equals(IType other) + { + ArrayType a = other as ArrayType; + return a != null && elementType.Equals(a.elementType) && a.dimensions == dimensions; + } + + public override ITypeReference ToTypeReference() + { + return new ArrayTypeReference(elementType.ToTypeReference(), dimensions); + } + + public override IEnumerable DirectBaseTypes { + get { + List baseTypes = new List(); + IType t = compilation.FindType(KnownTypeCode.Array); + if (t.Kind != TypeKind.Unknown) + baseTypes.Add(t); + if (dimensions == 1 && elementType.Kind != TypeKind.Pointer) { + // single-dimensional arrays implement IList + ITypeDefinition def = compilation.FindType(KnownTypeCode.IListOfT) as ITypeDefinition; + if (def != null) + baseTypes.Add(new ParameterizedType(def, new[] { elementType })); + // And in .NET 4.5 they also implement IReadOnlyList + def = compilation.FindType(KnownTypeCode.IReadOnlyListOfT) as ITypeDefinition; + if (def != null) + baseTypes.Add(new ParameterizedType(def, new[] { elementType })); + } + return baseTypes; + } + } + + public override IEnumerable GetMethods(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) + return EmptyList.Instance; + else + return compilation.FindType(KnownTypeCode.Array).GetMethods(filter, options); + } + + public override IEnumerable GetMethods(IList typeArguments, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) + return EmptyList.Instance; + else + return compilation.FindType(KnownTypeCode.Array).GetMethods(typeArguments, filter, options); + } + + public override IEnumerable GetAccessors(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) + return EmptyList.Instance; + else + return compilation.FindType(KnownTypeCode.Array).GetAccessors(filter, options); + } + + public override IEnumerable GetProperties(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) + return EmptyList.Instance; + else + return compilation.FindType(KnownTypeCode.Array).GetProperties(filter, options); + } + + // NestedTypes, Events, Fields: System.Array doesn't have any; so we can use the AbstractType default implementation + // that simply returns an empty list + + public override IType AcceptVisitor(TypeVisitor visitor) + { + return visitor.VisitArrayType(this); + } + + public override IType VisitChildren(TypeVisitor visitor) + { + IType e = elementType.AcceptVisitor(visitor); + if (e == elementType) + return this; + else + return new ArrayType(compilation, e, dimensions); + } + } + + [Serializable] + public sealed class ArrayTypeReference : ITypeReference, ISupportsInterning + { + readonly ITypeReference elementType; + readonly int dimensions; + + public ArrayTypeReference(ITypeReference elementType, int dimensions = 1) + { + if (elementType == null) + throw new ArgumentNullException("elementType"); + if (dimensions <= 0) + throw new ArgumentOutOfRangeException("dimensions", dimensions, "dimensions must be positive"); + this.elementType = elementType; + this.dimensions = dimensions; + } + + public ITypeReference ElementType { + get { return elementType; } + } + + public int Dimensions { + get { return dimensions; } + } + + public IType Resolve(ITypeResolveContext context) + { + return new ArrayType(context.Compilation, elementType.Resolve(context), dimensions); + } + + public override string ToString() + { + return elementType.ToString() + "[" + new string(',', dimensions - 1) + "]"; + } + + int ISupportsInterning.GetHashCodeForInterning() + { + return elementType.GetHashCode() ^ dimensions; + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + ArrayTypeReference o = other as ArrayTypeReference; + return o != null && elementType == o.elementType && dimensions == o.dimensions; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/AssemblyLoader.cs b/ICSharpCode.Decompiler/TypeSystem/AssemblyLoader.cs new file mode 100644 index 000000000..db230f461 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/AssemblyLoader.cs @@ -0,0 +1,94 @@ +// +// AssemblyLoader.cs +// +// Author: +// Mike Krüger +// +// Copyright (c) 2013 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.Reflection; +using System.Threading; +using ICSharpCode.NRefactory.Documentation; +using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.TypeSystem.Implementation; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + public enum AssemblyLoaderBackend { + Auto, + Cecil, + IKVM + } + + public abstract class AssemblyLoader + { + public static AssemblyLoader Create () + { + return Create (AssemblyLoaderBackend.Auto); + } + + public static AssemblyLoader Create (AssemblyLoaderBackend backend) + { + switch (backend) { + case AssemblyLoaderBackend.Auto: + case AssemblyLoaderBackend.Cecil: + return (AssemblyLoader)Assembly.Load ("ICSharpCode.NRefactory.Cecil").CreateInstance ("ICSharpCode.NRefactory.TypeSystem.CecilLoader"); + case AssemblyLoaderBackend.IKVM: + return (AssemblyLoader)Assembly.Load ("ICSharpCode.NRefactory.IKVM").CreateInstance ("ICSharpCode.NRefactory.TypeSystem.IkvmLoader"); + default: + throw new ArgumentOutOfRangeException (); + } + } + + /// + /// Specifies whether to include internal members. The default is false. + /// + public bool IncludeInternalMembers { get; set; } + + /// + /// Gets/Sets the cancellation token used by the assembly loader. + /// + public CancellationToken CancellationToken { get; set; } + + /// + /// Gets/Sets the documentation provider that is used to retrieve the XML documentation for all members. + /// + public IDocumentationProvider DocumentationProvider { get; set; } + + [CLSCompliant(false)] + protected InterningProvider interningProvider = new SimpleInterningProvider(); + + /// + /// Gets/Sets the interning provider. + /// + public InterningProvider InterningProvider { + get { return interningProvider; } + set { + if (value == null) + throw new ArgumentNullException(); + interningProvider = value; + } + } + + public abstract IUnresolvedAssembly LoadAssemblyFile(string fileName); + } +} + diff --git a/ICSharpCode.Decompiler/TypeSystem/AssemblyQualifiedTypeName.cs b/ICSharpCode.Decompiler/TypeSystem/AssemblyQualifiedTypeName.cs new file mode 100644 index 000000000..8b07c5197 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/AssemblyQualifiedTypeName.cs @@ -0,0 +1,79 @@ +// Copyright (c) 2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + public struct AssemblyQualifiedTypeName : IEquatable + { + public readonly string AssemblyName; + public readonly FullTypeName TypeName; + + public AssemblyQualifiedTypeName(FullTypeName typeName, string assemblyName) + { + this.AssemblyName = assemblyName; + this.TypeName = typeName; + } + + public AssemblyQualifiedTypeName(ITypeDefinition typeDefinition) + { + this.AssemblyName = typeDefinition.ParentAssembly.AssemblyName; + this.TypeName = typeDefinition.FullTypeName; + } + + public override string ToString() + { + if (string.IsNullOrEmpty(AssemblyName)) + return TypeName.ToString(); + else + return TypeName.ToString() + ", " + AssemblyName; + } + + public override bool Equals(object obj) + { + return (obj is AssemblyQualifiedTypeName) && Equals((AssemblyQualifiedTypeName)obj); + } + + public bool Equals(AssemblyQualifiedTypeName other) + { + return this.AssemblyName == other.AssemblyName && this.TypeName == other.TypeName; + } + + public override int GetHashCode() + { + int hashCode = 0; + unchecked { + if (AssemblyName != null) + hashCode += 1000000007 * AssemblyName.GetHashCode(); + hashCode += TypeName.GetHashCode(); + } + return hashCode; + } + + public static bool operator ==(AssemblyQualifiedTypeName lhs, AssemblyQualifiedTypeName rhs) + { + return lhs.Equals(rhs); + } + + public static bool operator !=(AssemblyQualifiedTypeName lhs, AssemblyQualifiedTypeName rhs) + { + return !lhs.Equals(rhs); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/ByReferenceType.cs b/ICSharpCode.Decompiler/TypeSystem/ByReferenceType.cs new file mode 100644 index 000000000..a7799de4e --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/ByReferenceType.cs @@ -0,0 +1,112 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.TypeSystem.Implementation; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + public sealed class ByReferenceType : TypeWithElementType + { + public ByReferenceType(IType elementType) : base(elementType) + { + } + + public override TypeKind Kind { + get { return TypeKind.ByReference; } + } + + public override string NameSuffix { + get { + return "&"; + } + } + + public override bool? IsReferenceType { + get { return null; } + } + + public override int GetHashCode() + { + return elementType.GetHashCode() ^ 91725813; + } + + public override bool Equals(IType other) + { + ByReferenceType a = other as ByReferenceType; + return a != null && elementType.Equals(a.elementType); + } + + public override IType AcceptVisitor(TypeVisitor visitor) + { + return visitor.VisitByReferenceType(this); + } + + public override IType VisitChildren(TypeVisitor visitor) + { + IType e = elementType.AcceptVisitor(visitor); + if (e == elementType) + return this; + else + return new ByReferenceType(e); + } + + public override ITypeReference ToTypeReference() + { + return new ByReferenceTypeReference(elementType.ToTypeReference()); + } + } + + [Serializable] + public sealed class ByReferenceTypeReference : ITypeReference, ISupportsInterning + { + readonly ITypeReference elementType; + + public ByReferenceTypeReference(ITypeReference elementType) + { + if (elementType == null) + throw new ArgumentNullException("elementType"); + this.elementType = elementType; + } + + public ITypeReference ElementType { + get { return elementType; } + } + + public IType Resolve(ITypeResolveContext context) + { + return new ByReferenceType(elementType.Resolve(context)); + } + + public override string ToString() + { + return elementType.ToString() + "&"; + } + + int ISupportsInterning.GetHashCodeForInterning() + { + return elementType.GetHashCode() ^ 91725814; + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + ByReferenceTypeReference brt = other as ByReferenceTypeReference; + return brt != null && this.elementType == brt.elementType; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/ComHelper.cs b/ICSharpCode.Decompiler/TypeSystem/ComHelper.cs new file mode 100644 index 000000000..3b7358059 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/ComHelper.cs @@ -0,0 +1,63 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Linq; +using ICSharpCode.NRefactory.Semantics; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Helper methods for COM. + /// + public static class ComHelper + { + static bool IsComAttribute(IAttribute attribute, string name) + { + return attribute.AttributeType.Name == name && attribute.AttributeType.Namespace == "System.Runtime.InteropServices"; + } + + /// + /// Gets whether the specified type is imported from COM. + /// + public static bool IsComImport(ITypeDefinition typeDefinition) + { + return typeDefinition != null + && typeDefinition.Kind == TypeKind.Interface + && typeDefinition.Attributes.Any(a => IsComAttribute(a, "ComImportAttribute")); + } + + /// + /// Gets the CoClass of the specified COM interface. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Co", + Justification = "Consistent with CoClassAttribute")] + public static IType GetCoClass(ITypeDefinition typeDefinition) + { + if (typeDefinition == null) + return SpecialType.UnknownType; + var coClassAttribute = typeDefinition.Attributes.FirstOrDefault(a => IsComAttribute(a, "CoClassAttribute")); + if (coClassAttribute != null && coClassAttribute.PositionalArguments.Count == 1) { + var rr = coClassAttribute.PositionalArguments[0] as TypeOfResolveResult; + if (rr != null) + return rr.ReferencedType; + } + return SpecialType.UnknownType; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/DefaultSolutionSnapshot.cs b/ICSharpCode.Decompiler/TypeSystem/DefaultSolutionSnapshot.cs new file mode 100644 index 000000000..c3b4bc534 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/DefaultSolutionSnapshot.cs @@ -0,0 +1,86 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Concurrent; +using System.Collections.Generic; + +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Default implementation of ISolutionSnapshot. + /// + public class DefaultSolutionSnapshot : ISolutionSnapshot + { + readonly Dictionary projectDictionary = new Dictionary(Platform.FileNameComparer); + ConcurrentDictionary dictionary = new ConcurrentDictionary(); + + /// + /// Creates a new DefaultSolutionSnapshot with the specified projects. + /// + public DefaultSolutionSnapshot(IEnumerable projects) + { + foreach (var project in projects) { + if (project.ProjectFileName != null) + projectDictionary.Add(project.ProjectFileName, project); + } + } + + /// + /// Creates a new DefaultSolutionSnapshot that does not support s. + /// + public DefaultSolutionSnapshot() + { + } + + public IProjectContent GetProjectContent(string projectFileName) + { + IProjectContent pc; + lock (projectDictionary) { + if (projectDictionary.TryGetValue(projectFileName, out pc)) + return pc; + else + return null; + } + } + + public ICompilation GetCompilation(IProjectContent project) + { + if (project == null) + throw new ArgumentNullException("project"); + return dictionary.GetOrAdd(project, p => p.CreateCompilation(this)); + } + + public void AddCompilation(IProjectContent project, ICompilation compilation) + { + if (project == null) + throw new ArgumentNullException("project"); + if (compilation == null) + throw new ArgumentNullException("compilation"); + if (!dictionary.TryAdd(project, compilation)) + throw new InvalidOperationException(); + if (project.ProjectFileName != null) { + lock (projectDictionary) { + projectDictionary.Add(project.ProjectFileName, project); + } + } + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/DomRegion.cs b/ICSharpCode.Decompiler/TypeSystem/DomRegion.cs new file mode 100644 index 000000000..11b0f794e --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/DomRegion.cs @@ -0,0 +1,230 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Globalization; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + [Serializable] + public struct DomRegion : IEquatable + { + readonly string fileName; + readonly int beginLine; + readonly int endLine; + readonly int beginColumn; + readonly int endColumn; + + public readonly static DomRegion Empty = new DomRegion(); + + public bool IsEmpty { + get { + return BeginLine <= 0; + } + } + + public string FileName { + get { return fileName; } + } + + public int BeginLine { + get { + return beginLine; + } + } + + /// + /// if the end line is == -1 the end column is -1 too + /// this stands for an unknwon end + /// + public int EndLine { + get { + return endLine; + } + } + + public int BeginColumn { + get { + return beginColumn; + } + } + + /// + /// if the end column is == -1 the end line is -1 too + /// this stands for an unknown end + /// + public int EndColumn { + get { + return endColumn; + } + } + + public TextLocation Begin { + get { + return new TextLocation (beginLine, beginColumn); + } + } + + public TextLocation End { + get { + return new TextLocation (endLine, endColumn); + } + } + + public DomRegion (int beginLine, int beginColumn, int endLine, int endColumn) : this (null, beginLine, beginColumn, endLine, endColumn) + { + } + + public DomRegion(string fileName, int beginLine, int beginColumn, int endLine, int endColumn) + { + this.fileName = fileName; + this.beginLine = beginLine; + this.beginColumn = beginColumn; + this.endLine = endLine; + this.endColumn = endColumn; + } + + public DomRegion (int beginLine, int beginColumn) : this (null, beginLine, beginColumn) + { + } + + public DomRegion (string fileName, int beginLine, int beginColumn) + { + this.fileName = fileName; + this.beginLine = beginLine; + this.beginColumn = beginColumn; + this.endLine = -1; + this.endColumn = -1; + } + + public DomRegion (TextLocation begin, TextLocation end) : this (null, begin, end) + { + } + + public DomRegion (string fileName, TextLocation begin, TextLocation end) + { + this.fileName = fileName; + this.beginLine = begin.Line; + this.beginColumn = begin.Column; + this.endLine = end.Line; + this.endColumn = end.Column; + } + + public DomRegion (TextLocation begin) : this (null, begin) + { + } + + public DomRegion (string fileName, TextLocation begin) + { + this.fileName = fileName; + this.beginLine = begin.Line; + this.beginColumn = begin.Column; + this.endLine = -1; + this.endColumn = -1; + } + + /// + /// Returns true, if the given coordinates (line, column) are in the region. + /// This method assumes that for an unknown end the end line is == -1 + /// + public bool IsInside(int line, int column) + { + if (IsEmpty) + return false; + return line >= BeginLine && + (line <= EndLine || EndLine == -1) && + (line != BeginLine || column >= BeginColumn) && + (line != EndLine || column <= EndColumn); + } + + public bool IsInside(TextLocation location) + { + return IsInside(location.Line, location.Column); + } + + /// + /// Returns true, if the given coordinates (line, column) are in the region. + /// This method assumes that for an unknown end the end line is == -1 + /// + public bool Contains(int line, int column) + { + if (IsEmpty) + return false; + return line >= BeginLine && + (line <= EndLine || EndLine == -1) && + (line != BeginLine || column >= BeginColumn) && + (line != EndLine || column < EndColumn); + } + + public bool Contains(TextLocation location) + { + return Contains(location.Line, location.Column); + } + + public bool IntersectsWith (DomRegion region) + { + return region.Begin <= End && region.End >= Begin; + } + + public bool OverlapsWith (DomRegion region) + { + var maxBegin = Begin > region.Begin ? Begin : region.Begin; + var minEnd = End < region.End ? End : region.End; + return maxBegin < minEnd; + } + + public override string ToString() + { + return string.Format( + CultureInfo.InvariantCulture, + "[DomRegion FileName={0}, Begin=({1}, {2}), End=({3}, {4})]", + fileName, beginLine, beginColumn, endLine, endColumn); + } + + public override bool Equals(object obj) + { + return obj is DomRegion && Equals((DomRegion)obj); + } + + public override int GetHashCode() + { + unchecked { + int hashCode = fileName != null ? fileName.GetHashCode() : 0; + hashCode ^= beginColumn + 1100009 * beginLine + 1200007 * endLine + 1300021 * endColumn; + return hashCode; + } + } + + public bool Equals(DomRegion other) + { + return beginLine == other.beginLine && beginColumn == other.beginColumn + && endLine == other.endLine && endColumn == other.endColumn + && fileName == other.fileName; + } + + public static bool operator ==(DomRegion left, DomRegion right) + { + return left.Equals(right); + } + + public static bool operator !=(DomRegion left, DomRegion right) + { + return !left.Equals(right); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/EntityType.cs b/ICSharpCode.Decompiler/TypeSystem/EntityType.cs new file mode 100644 index 000000000..b0124200a --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/EntityType.cs @@ -0,0 +1,63 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + [Obsolete("Use SymbolKind instead")] + public enum EntityType : byte + { + None = SymbolKind.None, + /// + TypeDefinition = SymbolKind.TypeDefinition, + /// + Field = SymbolKind.Field, + /// + /// The symbol is a property, but not an indexer. + /// + /// + Property = SymbolKind.Property, + /// + /// The symbol is an indexer, not a regular property. + /// + /// + Indexer = SymbolKind.Indexer, + /// + Event = SymbolKind.Event, + /// + /// The symbol is a method which is not an operator/constructor/destructor or accessor. + /// + /// + Method = SymbolKind.Method, + /// + /// The symbol is a user-defined operator. + /// + /// + Operator = SymbolKind.Operator, + /// + Constructor = SymbolKind.Constructor, + /// + Destructor = SymbolKind.Destructor, + /// + /// The accessor method for a property getter/setter or event add/remove. + /// + /// + Accessor = SymbolKind.Accessor, + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Error.cs b/ICSharpCode.Decompiler/TypeSystem/Error.cs new file mode 100644 index 000000000..ade3d45c8 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Error.cs @@ -0,0 +1,139 @@ +// +// Error.cs +// +// Author: +// Mike Krüger +// +// Copyright (c) 2011 Mike Krüger +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Enum that describes the type of an error. + /// + public enum ErrorType + { + Unknown, + Error, + Warning + } + + /// + /// Descibes an error during parsing. + /// + [Serializable] + public class Error + { + readonly ErrorType errorType; + readonly string message; + readonly DomRegion region; + + /// + /// The type of the error. + /// + public ErrorType ErrorType { get { return errorType; } } + + /// + /// The error description. + /// + public string Message { get { return message; } } + + /// + /// The region of the error. + /// + public DomRegion Region { get { return region; } } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The error type. + /// + /// + /// The description of the error. + /// + /// + /// The region of the error. + /// + public Error (ErrorType errorType, string message, DomRegion region) + { + this.errorType = errorType; + this.message = message; + this.region = region; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The error type. + /// + /// + /// The description of the error. + /// + /// + /// The location of the error. + /// + public Error (ErrorType errorType, string message, TextLocation location) + { + this.errorType = errorType; + this.message = message; + this.region = new DomRegion (location, location); + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The error type. + /// + /// + /// The description of the error. + /// + /// + /// The line of the error. + /// + /// + /// The column of the error. + /// + public Error (ErrorType errorType, string message, int line, int col) : this (errorType, message, new TextLocation (line, col)) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The error type. + /// + /// + /// The description of the error. + /// + public Error (ErrorType errorType, string message) + { + this.errorType = errorType; + this.message = message; + this.region = DomRegion.Empty; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/FullTypeName.cs b/ICSharpCode.Decompiler/TypeSystem/FullTypeName.cs new file mode 100644 index 000000000..b1bc888c4 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/FullTypeName.cs @@ -0,0 +1,315 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Text; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Holds the full name of a type definition. + /// A full type name uniquely identifies a type definition within a single assembly. + /// + /// + /// A full type name can only represent type definitions, not arbitrary types. + /// It does not include any type arguments, and can not refer to array or pointer types. + /// + /// A full type name represented as reflection name has the syntax: + /// NamespaceName '.' TopLevelTypeName ['`'#] { '+' NestedTypeName ['`'#] } + /// + [Serializable] + public struct FullTypeName : IEquatable + { + [Serializable] + struct NestedTypeName + { + public readonly string Name; + public readonly int AdditionalTypeParameterCount; + + public NestedTypeName(string name, int additionalTypeParameterCount) + { + if (name == null) + throw new ArgumentNullException("name"); + this.Name = name; + this.AdditionalTypeParameterCount = additionalTypeParameterCount; + } + } + + readonly TopLevelTypeName topLevelType; + readonly NestedTypeName[] nestedTypes; + + FullTypeName(TopLevelTypeName topLevelTypeName, NestedTypeName[] nestedTypes) + { + this.topLevelType = topLevelTypeName; + this.nestedTypes = nestedTypes; + } + + /// + /// Constructs a FullTypeName representing the given top-level type. + /// + /// + /// FullTypeName has an implicit conversion operator from TopLevelTypeName, + /// so you can simply write: + /// FullTypeName f = new TopLevelTypeName(...); + /// + public FullTypeName(TopLevelTypeName topLevelTypeName) + { + this.topLevelType = topLevelTypeName; + this.nestedTypes = null; + } + + /// + /// Constructs a FullTypeName by parsing the given reflection name. + /// Note that FullTypeName can only represent type definition names. If the reflection name + /// might refer to a parameterized type or array etc., use + /// instead. + /// + /// + /// Expected syntax: NamespaceName '.' TopLevelTypeName ['`'#] { '+' NestedTypeName ['`'#] } + /// where # are type parameter counts + /// + public FullTypeName(string reflectionName) + { + int pos = reflectionName.IndexOf('+'); + if (pos < 0) { + // top-level type + this.topLevelType = new TopLevelTypeName(reflectionName); + this.nestedTypes = null; + } else { + // nested type + string[] parts = reflectionName.Split('+'); + this.topLevelType = new TopLevelTypeName(parts[0]); + this.nestedTypes = new NestedTypeName[parts.Length - 1]; + for (int i = 0; i < nestedTypes.Length; i++) { + int tpc; + string name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(parts[i + 1], out tpc); + nestedTypes[i] = new NestedTypeName(name, tpc); + } + } + } + + /// + /// Gets the top-level type name. + /// + public TopLevelTypeName TopLevelTypeName { + get { return topLevelType; } + } + + /// + /// Gets whether this is a nested type. + /// + public bool IsNested { + get { + return nestedTypes != null; + } + } + + /// + /// Gets the nesting level. + /// + public int NestingLevel { + get { + return nestedTypes != null ? nestedTypes.Length : 0; + } + } + + /// + /// Gets the name of the type. + /// For nested types, this is the name of the innermost type. + /// + public string Name { + get { + if (nestedTypes != null) + return nestedTypes[nestedTypes.Length - 1].Name; + else + return topLevelType.Name; + } + } + + public string ReflectionName { + get { + if (nestedTypes == null) + return topLevelType.ReflectionName; + StringBuilder b = new StringBuilder(topLevelType.ReflectionName); + foreach (NestedTypeName nt in nestedTypes) { + b.Append('+'); + b.Append(nt.Name); + if (nt.AdditionalTypeParameterCount > 0) { + b.Append('`'); + b.Append(nt.AdditionalTypeParameterCount); + } + } + return b.ToString(); + } + } + + /// + /// Gets the total type parameter count. + /// + public int TypeParameterCount { + get { + int tpc = topLevelType.TypeParameterCount; + if (nestedTypes != null) { + foreach (var nt in nestedTypes) { + tpc += nt.AdditionalTypeParameterCount; + } + } + return tpc; + } + } + + /// + /// Gets the name of the nested type at the given level. + /// + public string GetNestedTypeName(int nestingLevel) + { + if (nestedTypes == null) + throw new InvalidOperationException(); + return nestedTypes[nestingLevel].Name; + } + + /// + /// Gets the number of additional type parameters of the nested type at the given level. + /// + public int GetNestedTypeAdditionalTypeParameterCount(int nestingLevel) + { + if (nestedTypes == null) + throw new InvalidOperationException(); + return nestedTypes[nestingLevel].AdditionalTypeParameterCount; + } + + /// + /// Gets the declaring type name. + /// + /// This is a top-level type name. + /// new FullTypeName("NS.A+B+C").GetDeclaringType() will return new FullTypeName("NS.A+B") + public FullTypeName GetDeclaringType() + { + if (nestedTypes == null) + throw new InvalidOperationException(); + if (nestedTypes.Length == 1) + return topLevelType; + NestedTypeName[] outerNestedTypeNames = new NestedTypeName[nestedTypes.Length - 1]; + Array.Copy(nestedTypes, 0, outerNestedTypeNames, 0, outerNestedTypeNames.Length); + return new FullTypeName(topLevelType, nestedTypes); + } + + /// + /// Creates a nested type name. + /// + /// new FullTypeName("NS.A+B").NestedType("C", 1) will return new FullTypeName("NS.A+B+C`1") + public FullTypeName NestedType(string name, int additionalTypeParameterCount) + { + if (name == null) + throw new ArgumentNullException("name"); + var newNestedType = new NestedTypeName(name, additionalTypeParameterCount); + if (nestedTypes == null) + return new FullTypeName(topLevelType, new[] { newNestedType }); + NestedTypeName[] newNestedTypeNames = new NestedTypeName[nestedTypes.Length + 1]; + nestedTypes.CopyTo(newNestedTypeNames, 0); + newNestedTypeNames[newNestedTypeNames.Length - 1] = newNestedType; + return new FullTypeName(topLevelType, newNestedTypeNames); + } + + public static implicit operator FullTypeName(TopLevelTypeName topLevelTypeName) + { + return new FullTypeName(topLevelTypeName); + } + + public override string ToString() + { + return this.ReflectionName; + } + + #region Equals and GetHashCode implementation + public override bool Equals(object obj) + { + return obj is FullTypeName && Equals((FullTypeName)obj); + } + + public bool Equals(FullTypeName other) + { + return FullTypeNameComparer.Ordinal.Equals(this, other); + } + + public override int GetHashCode() + { + return FullTypeNameComparer.Ordinal.GetHashCode(this); + } + + public static bool operator ==(FullTypeName left, FullTypeName right) + { + return left.Equals(right); + } + + public static bool operator !=(FullTypeName left, FullTypeName right) + { + return !left.Equals(right); + } + #endregion + } + + [Serializable] + public sealed class FullTypeNameComparer : IEqualityComparer + { + public static readonly FullTypeNameComparer Ordinal = new FullTypeNameComparer(StringComparer.Ordinal); + public static readonly FullTypeNameComparer OrdinalIgnoreCase = new FullTypeNameComparer(StringComparer.OrdinalIgnoreCase); + + public readonly StringComparer NameComparer; + + public FullTypeNameComparer(StringComparer nameComparer) + { + this.NameComparer = nameComparer; + } + + public bool Equals(FullTypeName x, FullTypeName y) + { + if (x.NestingLevel != y.NestingLevel) + return false; + TopLevelTypeName topX = x.TopLevelTypeName; + TopLevelTypeName topY = y.TopLevelTypeName; + if (topX.TypeParameterCount == topY.TypeParameterCount + && NameComparer.Equals(topX.Name, topY.Name) + && NameComparer.Equals(topX.Namespace, topY.Namespace)) + { + for (int i = 0; i < x.NestingLevel; i++) { + if (x.GetNestedTypeAdditionalTypeParameterCount(i) != y.GetNestedTypeAdditionalTypeParameterCount(i)) + return false; + if (!NameComparer.Equals(x.GetNestedTypeName(i), y.GetNestedTypeName(i))) + return false; + } + return true; + } + return false; + } + + public int GetHashCode(FullTypeName obj) + { + TopLevelTypeName top = obj.TopLevelTypeName; + int hash = NameComparer.GetHashCode(top.Name) ^ NameComparer.GetHashCode(top.Namespace) ^ top.TypeParameterCount; + unchecked { + for (int i = 0; i < obj.NestingLevel; i++) { + hash *= 31; + hash += NameComparer.GetHashCode(obj.Name) ^ obj.TypeParameterCount; + } + } + return hash; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/IAmbience.cs b/ICSharpCode.Decompiler/TypeSystem/IAmbience.cs new file mode 100644 index 000000000..18beccfa6 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/IAmbience.cs @@ -0,0 +1,107 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + [Flags] + public enum ConversionFlags + { + /// + /// Convert only the name. + /// + None = 0, + /// + /// Show the parameter list + /// + ShowParameterList = 1, + /// + /// Show names for parameters + /// + ShowParameterNames = 2, + /// + /// Show the accessibility (private, public, etc.) + /// + ShowAccessibility = 4, + /// + /// Show the definition key word (class, struct, Sub, Function, etc.) + /// + ShowDefinitionKeyword = 8, + /// + /// Show the declaring type for the member + /// + ShowDeclaringType = 0x10, + /// + /// Show modifiers (virtual, override, etc.) + /// + ShowModifiers = 0x20, + /// + /// Show the return type + /// + ShowReturnType = 0x40, + /// + /// Use fully qualified names for types. + /// + UseFullyQualifiedTypeNames = 0x80, + /// + /// Show the list of type parameters on method and class declarations. + /// Type arguments for parameter/return types are always shown. + /// + ShowTypeParameterList = 0x100, + /// + /// For fields, events and methods: adds a semicolon at the end. + /// For properties: shows "{ get; }" or similar. + /// + ShowBody = 0x200, + + /// + /// Use fully qualified names for members. + /// + UseFullyQualifiedEntityNames = 0x400, + + StandardConversionFlags = ShowParameterNames | + ShowAccessibility | + ShowParameterList | + ShowReturnType | + ShowModifiers | + ShowTypeParameterList | + ShowDefinitionKeyword | + ShowBody, + + All = 0x7ff, + } + + /// + /// Ambiences are used to convert type system symbols to text (usually for displaying the symbol to the user; e.g. in editor tooltips). + /// + public interface IAmbience + { + ConversionFlags ConversionFlags { get; set; } + + [Obsolete("Use ConvertSymbol() instead")] + string ConvertEntity(IEntity entity); + string ConvertSymbol(ISymbol symbol); + string ConvertType(IType type); + [Obsolete("Use ConvertSymbol() instead")] + string ConvertVariable(IVariable variable); + string ConvertConstantValue(object constantValue); + + string WrapComment(string comment); + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/IAssembly.cs b/ICSharpCode.Decompiler/TypeSystem/IAssembly.cs new file mode 100644 index 000000000..9dcb69f9c --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/IAssembly.cs @@ -0,0 +1,128 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Represents an unresolved assembly. + /// + public interface IUnresolvedAssembly : IAssemblyReference + { + /// + /// Gets the assembly name (short name). + /// + string AssemblyName { get; } + + /// + /// Gets the full assembly name (including public key token etc.) + /// + string FullAssemblyName { get; } + + /// + /// Gets the path to the assembly location. + /// For projects it is the same as the output path. + /// + string Location { get; } + + /// + /// Gets the list of all assembly attributes in the project. + /// + IEnumerable AssemblyAttributes { get; } + + /// + /// Gets the list of all module attributes in the project. + /// + IEnumerable ModuleAttributes { get; } + + /// + /// Gets all non-nested types in the assembly. + /// + IEnumerable TopLevelTypeDefinitions { get; } + } + + public interface IAssemblyReference + { + /// + /// Resolves this assembly. + /// + IAssembly Resolve(ITypeResolveContext context); + } + + /// + /// Represents an assembly. + /// + public interface IAssembly : ICompilationProvider + { + /// + /// Gets the original unresolved assembly. + /// + IUnresolvedAssembly UnresolvedAssembly { get; } + + /// + /// Gets whether this assembly is the main assembly of the compilation. + /// + bool IsMainAssembly { get; } + + /// + /// Gets the assembly name (short name). + /// + string AssemblyName { get; } + + /// + /// Gets the full assembly name (including public key token etc.) + /// + string FullAssemblyName { get; } + + /// + /// Gets the list of all assembly attributes in the project. + /// + IList AssemblyAttributes { get; } + + /// + /// Gets the list of all module attributes in the project. + /// + IList ModuleAttributes { get; } + + /// + /// Gets whether the internals of this assembly are visible in the specified assembly. + /// + bool InternalsVisibleTo(IAssembly assembly); + + /// + /// Gets the root namespace for this assembly. + /// + /// + /// This always is the namespace without a name - it's unrelated to the 'root namespace' project setting. + /// + INamespace RootNamespace { get; } + + /// + /// Gets the type definition for a top-level type. + /// + /// This method uses ordinal name comparison, not the compilation's name comparer. + ITypeDefinition GetTypeDefinition(TopLevelTypeName topLevelTypeName); + + /// + /// Gets all non-nested types in the assembly. + /// + IEnumerable TopLevelTypeDefinitions { get; } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/IAttribute.cs b/ICSharpCode.Decompiler/TypeSystem/IAttribute.cs new file mode 100644 index 000000000..0689aebbe --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/IAttribute.cs @@ -0,0 +1,75 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Semantics; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Represents an unresolved attribute. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")] + public interface IUnresolvedAttribute + { + /// + /// Gets the code region of this attribute. + /// + DomRegion Region { get; } + + /// + /// Resolves the attribute. + /// + IAttribute CreateResolvedAttribute(ITypeResolveContext context); + } + + /// + /// Represents an attribute. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")] + public interface IAttribute + { + /// + /// Gets the code region of this attribute. + /// + DomRegion Region { get; } + + /// + /// Gets the type of the attribute. + /// + IType AttributeType { get; } + + /// + /// Gets the constructor being used. + /// This property may return null if no matching constructor was found. + /// + IMethod Constructor { get; } + + /// + /// Gets the positional arguments. + /// + IList PositionalArguments { get; } + + /// + /// Gets the named arguments passed to the attribute. + /// + IList> NamedArguments { get; } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/ICodeContext.cs b/ICSharpCode.Decompiler/TypeSystem/ICodeContext.cs new file mode 100644 index 000000000..407673375 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/ICodeContext.cs @@ -0,0 +1,38 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + public interface ICodeContext : ITypeResolveContext + { + /// + /// Gets all currently visible local variables and lambda parameters. + /// Does not include method parameters. + /// + IEnumerable LocalVariables { get; } + + /// + /// Gets whether the context is within a lambda expression or anonymous method. + /// + bool IsWithinLambdaExpression { get; } + } +} + diff --git a/ICSharpCode.Decompiler/TypeSystem/ICompilation.cs b/ICSharpCode.Decompiler/TypeSystem/ICompilation.cs new file mode 100644 index 000000000..308bf24b1 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/ICompilation.cs @@ -0,0 +1,91 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + public interface ICompilation + { + /// + /// Gets the current assembly. + /// + IAssembly MainAssembly { get; } + + /// + /// Gets the type resolve context that specifies this compilation and no current assembly or entity. + /// + ITypeResolveContext TypeResolveContext { get; } + + /// + /// Gets the list of all assemblies in the compilation. + /// + /// + /// This main assembly is the first entry in the list. + /// + IList Assemblies { get; } + + /// + /// Gets the referenced assemblies. + /// This list does not include the main assembly. + /// + IList ReferencedAssemblies { get; } + + /// + /// Gets the root namespace of this compilation. + /// This is a merged version of the root namespaces of all assemblies. + /// + /// + /// This always is the namespace without a name - it's unrelated to the 'root namespace' project setting. + /// + INamespace RootNamespace { get; } + + /// + /// Gets the root namespace for a given extern alias. + /// + /// + /// If is null or an empty string, this method + /// returns the global root namespace. + /// If no alias with the specified name exists, this method returns null. + /// + INamespace GetNamespaceForExternAlias(string alias); + + IType FindType(KnownTypeCode typeCode); + + /// + /// Gets the name comparer for the language being compiled. + /// This is the string comparer used for the INamespace.GetTypeDefinition method. + /// + StringComparer NameComparer { get; } + + ISolutionSnapshot SolutionSnapshot { get; } + + CacheManager CacheManager { get; } + } + + public interface ICompilationProvider + { + /// + /// Gets the parent compilation. + /// This property never returns null. + /// + ICompilation Compilation { get; } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/IConstantValue.cs b/ICSharpCode.Decompiler/TypeSystem/IConstantValue.cs new file mode 100644 index 000000000..30df08f3e --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/IConstantValue.cs @@ -0,0 +1,38 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Diagnostics.Contracts; +using ICSharpCode.NRefactory.Semantics; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Represents an unresolved constant value. + /// + public interface IConstantValue + { + /// + /// Resolves the value of this constant. + /// + /// Context where the constant value will be used. + /// Resolve result representing the constant value. + /// This method never returns null; in case of errors, an ErrorResolveResult will be returned. + ResolveResult Resolve(ITypeResolveContext context); + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/IEntity.cs b/ICSharpCode.Decompiler/TypeSystem/IEntity.cs new file mode 100644 index 000000000..85d69ca4b --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/IEntity.cs @@ -0,0 +1,178 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Diagnostics.Contracts; +using ICSharpCode.NRefactory.Documentation; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Represents an unresolved entity. + /// + public interface IUnresolvedEntity : INamedElement, IHasAccessibility + { + /// + /// Gets the entity type. + /// + SymbolKind SymbolKind { get; } + + /// + /// Gets the complete entity region (including header+body) + /// + DomRegion Region { get; } + + /// + /// Gets the entity body region. + /// + DomRegion BodyRegion { get; } + + /// + /// Gets the declaring class. + /// For members, this is the class that contains the member. + /// For nested classes, this is the outer class. For top-level entities, this property returns null. + /// + IUnresolvedTypeDefinition DeclaringTypeDefinition { get; } + + /// + /// Gets the parsed file in which this entity is defined. + /// Returns null if this entity wasn't parsed from source code (e.g. loaded from a .dll with CecilLoader). + /// + IUnresolvedFile UnresolvedFile { get; } + + /// + /// Gets the attributes on this entity. + /// + IList Attributes { get; } + + /// + /// Gets whether this entity is static. + /// Returns true if either the 'static' or the 'const' modifier is set. + /// + bool IsStatic { get; } + + /// + /// Returns whether this entity is abstract. + /// + /// Static classes also count as abstract classes. + bool IsAbstract { get; } + + /// + /// Returns whether this entity is sealed. + /// + /// Static classes also count as sealed classes. + bool IsSealed { get; } + + /// + /// Gets whether this member is declared to be shadowing another member with the same name. + /// + bool IsShadowing { get; } + + /// + /// Gets whether this member is generated by a macro/compiler feature. + /// + bool IsSynthetic { get; } + } + + /// + /// Represents a resolved entity. + /// + public interface IEntity : ISymbol, ICompilationProvider, INamedElement, IHasAccessibility + { + /// + /// Gets the entity type. + /// + [Obsolete("Use the SymbolKind property instead.")] + EntityType EntityType { get; } + + /// + /// Gets the short name of the entity. + /// + new string Name { get; } + + /// + /// Gets the complete entity region (including header+body) + /// + DomRegion Region { get; } + + /// + /// Gets the entity body region. + /// + DomRegion BodyRegion { get; } + + /// + /// Gets the declaring class. + /// For members, this is the class that contains the member. + /// For nested classes, this is the outer class. For top-level entities, this property returns null. + /// + ITypeDefinition DeclaringTypeDefinition { get; } + + /// + /// Gets/Sets the declaring type (incl. type arguments, if any). + /// This property will return null for top-level entities. + /// If this is not a specialized member, the value returned is equal to . + /// + IType DeclaringType { get; } + + /// + /// The assembly in which this entity is defined. + /// This property never returns null. + /// + IAssembly ParentAssembly { get; } + + /// + /// Gets the attributes on this entity. + /// + IList Attributes { get; } + + /// + /// Gets the documentation for this entity. + /// + DocumentationComment Documentation { get; } + + /// + /// Gets whether this entity is static. + /// Returns true if either the 'static' or the 'const' modifier is set. + /// + bool IsStatic { get; } + + /// + /// Returns whether this entity is abstract. + /// + /// Static classes also count as abstract classes. + bool IsAbstract { get; } + + /// + /// Returns whether this entity is sealed. + /// + /// Static classes also count as sealed classes. + bool IsSealed { get; } + + /// + /// Gets whether this member is declared to be shadowing another member with the same name. + /// (C# 'new' keyword) + /// + bool IsShadowing { get; } + + /// + /// Gets whether this member is generated by a macro/compiler feature. + /// + bool IsSynthetic { get; } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/IEvent.cs b/ICSharpCode.Decompiler/TypeSystem/IEvent.cs new file mode 100644 index 000000000..f8d9c675c --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/IEvent.cs @@ -0,0 +1,58 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Diagnostics.Contracts; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + public interface IUnresolvedEvent : IUnresolvedMember + { + bool CanAdd { get; } + bool CanRemove { get; } + bool CanInvoke { get; } + + IUnresolvedMethod AddAccessor { get; } + IUnresolvedMethod RemoveAccessor { get; } + IUnresolvedMethod InvokeAccessor { get; } + + /// + /// Resolves the member. + /// + /// + /// Context for looking up the member. The context must specify the current assembly. + /// A that specifies the current assembly is sufficient. + /// + /// + /// Returns the resolved member, or null if the member could not be found. + /// + new IEvent Resolve(ITypeResolveContext context); + } + + public interface IEvent : IMember + { + bool CanAdd { get; } + bool CanRemove { get; } + bool CanInvoke { get; } + + IMethod AddAccessor { get; } + IMethod RemoveAccessor { get; } + IMethod InvokeAccessor { get; } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/IField.cs b/ICSharpCode.Decompiler/TypeSystem/IField.cs new file mode 100644 index 000000000..98fa0efe3 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/IField.cs @@ -0,0 +1,99 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Diagnostics.Contracts; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Represents a field or constant. + /// + public interface IUnresolvedField : IUnresolvedMember + { + /// + /// Gets whether this field is readonly. + /// + bool IsReadOnly { get; } + + /// + /// Gets whether this field is volatile. + /// + bool IsVolatile { get; } + + /// + /// Gets whether this field is a constant (C#-like const). + /// + bool IsConst { get; } + + /// + /// Gets whether this field is a fixed size buffer (C#-like fixed). + /// If this is true, then ConstantValue contains the size of the buffer. + /// + bool IsFixed { get; } + + + IConstantValue ConstantValue { get; } + + /// + /// Resolves the member. + /// + /// + /// Context for looking up the member. The context must specify the current assembly. + /// A that specifies the current assembly is sufficient. + /// + /// + /// Returns the resolved member, or null if the member could not be found. + /// + new IField Resolve(ITypeResolveContext context); + } + + /// + /// Represents a field or constant. + /// + public interface IField : IMember, IVariable + { + /// + /// Gets the name of the field. + /// + new string Name { get; } // solve ambiguity between IMember.Name and IVariable.Name + + /// + /// Gets the region where the field is declared. + /// + new DomRegion Region { get; } // solve ambiguity between IEntity.Region and IVariable.Region + + /// + /// Gets whether this field is readonly. + /// + bool IsReadOnly { get; } + + /// + /// Gets whether this field is volatile. + /// + bool IsVolatile { get; } + + /// + /// Gets whether this field is a fixed size buffer (C#-like fixed). + /// If this is true, then ConstantValue contains the size of the buffer. + /// + bool IsFixed { get; } + + new IMemberReference ToReference(); // solve ambiguity between IMember.ToReference() and IVariable.ToReference() + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/IFreezable.cs b/ICSharpCode.Decompiler/TypeSystem/IFreezable.cs new file mode 100644 index 000000000..3a0c66591 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/IFreezable.cs @@ -0,0 +1,35 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + public interface IFreezable + { + /// + /// Gets if this instance is frozen. Frozen instances are immutable and thus thread-safe. + /// + bool IsFrozen { get; } + + /// + /// Freezes this instance. + /// + void Freeze(); + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/IInterningProvider.cs b/ICSharpCode.Decompiler/TypeSystem/IInterningProvider.cs new file mode 100644 index 000000000..6f80d4a98 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/IInterningProvider.cs @@ -0,0 +1,102 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Provider used for interning. + /// + /// + /// A simple IInterningProvider implementation could use 3 dictionaries: + /// 1. using value equality comparer (for certain types known to implement value equality, e.g. string and IType) + /// 2. using comparer that calls into ISupportsInterning (for types implementing ISupportsInterning) + /// 3. list comparer (for InternList method) + /// + /// On the first Intern()-call, the provider tells the object to prepare for interning (ISupportsInterning.PrepareForInterning) + /// and stores it into a dictionary. On further Intern() calls, the original object is returned for all equal objects. + /// This allows reducing the memory usage by using a single object instance where possible. + /// + /// Interning provider implementations could also use the interning logic for different purposes: + /// for example, it could be used to determine which objects are used jointly between multiple type definitions + /// and which are used only within a single type definition. Then a persistent file format could be organized so + /// that shared objects are loaded only once, yet non-shared objects get loaded lazily together with the class. + /// + public abstract class InterningProvider + { + public static readonly InterningProvider Dummy = new DummyInterningProvider(); + + /// + /// Interns the specified object. + /// + /// If the object is freezable, it will be frozen. + /// + public abstract ISupportsInterning Intern(ISupportsInterning obj); + + /// + /// Interns the specified object. + /// + /// If the object is freezable, it will be frozen. + /// + public T Intern(T obj) where T : class, ISupportsInterning + { + ISupportsInterning input = obj; + return (T)Intern(input); + } + + /// + /// Interns the specified string. + /// + public abstract string Intern(string text); + + /// + /// Inters a boxed value type. + /// + public abstract object InternValue(object obj); + + /// + /// Interns the given list. Uses reference equality to compare the list elements. + /// + public abstract IList InternList(IList list) where T : class; + + sealed class DummyInterningProvider : InterningProvider + { + public override ISupportsInterning Intern(ISupportsInterning obj) + { + return obj; + } + + public override string Intern(string text) + { + return text; + } + + public override object InternValue(object obj) + { + return obj; + } + + public override IList InternList(IList list) + { + return list; + } + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/IMember.cs b/ICSharpCode.Decompiler/TypeSystem/IMember.cs new file mode 100644 index 000000000..405dc5184 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/IMember.cs @@ -0,0 +1,196 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Method/field/property/event. + /// + public interface IUnresolvedMember : IUnresolvedEntity, IMemberReference + { + /// + /// Gets the return type of this member. + /// This property never returns null. + /// + ITypeReference ReturnType { get; } + + /// + /// Gets whether this member is explicitly implementing an interface. + /// If this property is true, the member can only be called through the interfaces it implements. + /// + bool IsExplicitInterfaceImplementation { get; } + + /// + /// Gets the interfaces that are explicitly implemented by this member. + /// + IList ExplicitInterfaceImplementations { get; } + + /// + /// Gets if the member is virtual. Is true only if the "virtual" modifier was used, but non-virtual + /// members can be overridden, too; if they are abstract or overriding a method. + /// + bool IsVirtual { get; } + + /// + /// Gets whether this member is overriding another member. + /// + bool IsOverride { get; } + + /// + /// Gets if the member can be overridden. Returns true when the member is "abstract", "virtual" or "override" but not "sealed". + /// + bool IsOverridable { get; } + + /// + /// Resolves the member. + /// + /// + /// Context for looking up the member. The context must specify the current assembly. + /// A that specifies the current assembly is sufficient. + /// + /// + /// Returns the resolved member, or null if the member could not be found. + /// + new IMember Resolve(ITypeResolveContext context); + + /// + /// Creates the resolved member. + /// + /// + /// The language-specific context that includes the parent type definition. + /// + /// + IMember CreateResolved(ITypeResolveContext context); + } + + public interface IMemberReference : ISymbolReference + { + /// + /// Gets the declaring type reference for the member. + /// + ITypeReference DeclaringTypeReference { get; } + + /// + /// Resolves the member. + /// + /// + /// Context to use for resolving this member reference. + /// Which kind of context is required depends on the which kind of member reference this is; + /// please consult the documentation of the method that was used to create this member reference, + /// or that of the class implementing this method. + /// + /// + /// Returns the resolved member, or null if the member could not be found. + /// + new IMember Resolve(ITypeResolveContext context); + } + + /// + /// Method/field/property/event. + /// + public interface IMember : IEntity + { + /// + /// Gets the original member definition for this member. + /// Returns this if this is not a specialized member. + /// Specialized members are the result of overload resolution with type substitution. + /// + IMember MemberDefinition { get; } + + /// + /// Gets the unresolved member instance from which this member was created. + /// This property may return null for special members that do not have a corresponding unresolved member instance. + /// + /// + /// For specialized members, this property returns the unresolved member for the original member definition. + /// For partial methods, this property returns the implementing partial method declaration, if one exists, and the + /// defining partial method declaration otherwise. + /// For the members used to represent the built-in C# operators like "operator +(int, int);", this property returns null. + /// + IUnresolvedMember UnresolvedMember { get; } + + /// + /// Gets the return type of this member. + /// This property never returns null. + /// + IType ReturnType { get; } + + /// + /// Gets the interface members implemented by this member (both implicitly and explicitly). + /// + IList ImplementedInterfaceMembers { get; } + + /// + /// Gets whether this member is explicitly implementing an interface. + /// + bool IsExplicitInterfaceImplementation { get; } + + /// + /// Gets if the member is virtual. Is true only if the "virtual" modifier was used, but non-virtual + /// members can be overridden, too; if they are abstract or overriding a method. + /// + bool IsVirtual { get; } + + /// + /// Gets whether this member is overriding another member. + /// + bool IsOverride { get; } + + /// + /// Gets if the member can be overridden. Returns true when the member is "abstract", "virtual" or "override" but not "sealed". + /// + bool IsOverridable { get; } + + /// + /// Creates a member reference that can be used to rediscover this member in another compilation. + /// + /// + /// If this member is specialized using open generic types, the resulting member reference will need to be looked up in an appropriate generic context. + /// Otherwise, the main resolve context of a compilation is sufficient. + /// + [Obsolete("Use the ToReference method instead.")] + IMemberReference ToMemberReference(); + + /// + /// Creates a member reference that can be used to rediscover this member in another compilation. + /// + /// + /// If this member is specialized using open generic types, the resulting member reference will need to be looked up in an appropriate generic context. + /// Otherwise, the main resolve context of a compilation is sufficient. + /// + new IMemberReference ToReference(); + + /// + /// Gets the substitution belonging to this specialized member. + /// Returns TypeParameterSubstitution.Identity for not specialized members. + /// + TypeParameterSubstitution Substitution { + get; + } + + /// + /// Specializes this member with the given substitution. + /// If this member is already specialized, the new substitution is composed with the existing substition. + /// + IMember Specialize(TypeParameterSubstitution substitution); + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/IMethod.cs b/ICSharpCode.Decompiler/TypeSystem/IMethod.cs new file mode 100644 index 000000000..d73616d35 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/IMethod.cs @@ -0,0 +1,168 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Diagnostics.Contracts; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + public interface IUnresolvedMethod : IUnresolvedParameterizedMember + { + /// + /// Gets the attributes associated with the return type. (e.g. [return: MarshalAs(...)]) + /// + IList ReturnTypeAttributes { get; } + + IList TypeParameters { get; } + + bool IsConstructor { get; } + bool IsDestructor { get; } + bool IsOperator { get; } + + /// + /// Gets whether the method is a C#-style partial method. + /// Check to test if it is a partial method declaration or implementation. + /// + bool IsPartial { get; } + + /// + /// Gets whether the method is a C#-style async method. + /// + bool IsAsync { get; } + + [Obsolete("Use IsPartial && !HasBody instead")] + bool IsPartialMethodDeclaration { get; } + + [Obsolete("Use IsPartial && HasBody instead")] + bool IsPartialMethodImplementation { get; } + + /// + /// Gets whether the method has a body. + /// This property returns false for abstract or extern methods, + /// or for partial methods without implementation. + /// + bool HasBody { get; } + + /// + /// If this method is an accessor, returns a reference to the corresponding property/event. + /// Otherwise, returns null. + /// + IUnresolvedMember AccessorOwner { get; } + + /// + /// Resolves the member. + /// + /// + /// Context for looking up the member. The context must specify the current assembly. + /// A that specifies the current assembly is sufficient. + /// + /// + /// Returns the resolved member, or null if the member could not be found. + /// + new IMethod Resolve(ITypeResolveContext context); + } + + /// + /// Represents a method, constructor, destructor or operator. + /// + public interface IMethod : IParameterizedMember + { + /// + /// Gets the unresolved method parts. + /// For partial methods, this returns all parts. + /// Otherwise, this returns an array with a single element (new[] { UnresolvedMember }). + /// NOTE: The type will change to IReadOnlyList<IUnresolvedMethod> in future versions. + /// + IList Parts { get; } + + /// + /// Gets the attributes associated with the return type. (e.g. [return: MarshalAs(...)]) + /// NOTE: The type will change to IReadOnlyList<IAttribute> in future versions. + /// + IList ReturnTypeAttributes { get; } + + /// + /// Gets the type parameters of this method; or an empty list if the method is not generic. + /// NOTE: The type will change to IReadOnlyList<ITypeParameter> in future versions. + /// + IList TypeParameters { get; } + + /// + /// Gets whether this is a generic method that has been parameterized. + /// + bool IsParameterized { get; } + + /// + /// Gets the type arguments passed to this method. + /// If the method is generic but not parameterized yet, this property returns the type parameters, + /// as if the method was parameterized with its own type arguments (void M<T>() { M<T>(); }). + /// + /// NOTE: The type will change to IReadOnlyList<IType> in future versions. + /// + IList TypeArguments { get; } + + bool IsExtensionMethod { get; } + bool IsConstructor { get; } + bool IsDestructor { get; } + bool IsOperator { get; } + + /// + /// Gets whether the method is a C#-style partial method. + /// A call to such a method is ignored by the compiler if the partial method has no body. + /// + /// + bool IsPartial { get; } + + /// + /// Gets whether the method is a C#-style async method. + /// + bool IsAsync { get; } + + /// + /// Gets whether the method has a body. + /// This property returns false for abstract or extern methods, + /// or for partial methods without implementation. + /// + bool HasBody { get; } + + /// + /// Gets whether the method is a property/event accessor. + /// + bool IsAccessor { get; } + + /// + /// If this method is an accessor, returns the corresponding property/event. + /// Otherwise, returns null. + /// + IMember AccessorOwner { get; } + + /// + /// If this method is reduced from an extension method return the original method, null otherwise. + /// A reduced method doesn't contain the extension method parameter. That means that has one parameter less than it's definition. + /// + IMethod ReducedFrom { get; } + + /// + /// Specializes this method with the given substitution. + /// If this method is already specialized, the new substitution is composed with the existing substition. + /// + new IMethod Specialize(TypeParameterSubstitution substitution); + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/INamedElement.cs b/ICSharpCode.Decompiler/TypeSystem/INamedElement.cs new file mode 100644 index 000000000..4a4aff26c --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/INamedElement.cs @@ -0,0 +1,66 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Diagnostics.Contracts; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + public interface INamedElement + { + /// + /// Gets the fully qualified name of the class the return type is pointing to. + /// + /// + /// "System.Int32[]" for int[]
+ /// "System.Collections.Generic.List" for List<string> + /// "System.Environment.SpecialFolder" for Environment.SpecialFolder + ///
+ string FullName { get; } + + /// + /// Gets the short name of the class the return type is pointing to. + /// + /// + /// "Int32[]" for int[]
+ /// "List" for List<string> + /// "SpecialFolder" for Environment.SpecialFolder + ///
+ string Name { get; } + + /// + /// Gets the full reflection name of the element. + /// + /// + /// For types, the reflection name can be parsed back into a ITypeReference by using + /// . + /// + /// + /// "System.Int32[]" for int[]
+ /// "System.Int32[][,]" for C# int[,][]
+ /// "System.Collections.Generic.List`1[[System.String]]" for List<string> + /// "System.Environment+SpecialFolder" for Environment.SpecialFolder + ///
+ string ReflectionName { get; } + + /// + /// Gets the full name of the namespace containing this entity. + /// + string Namespace { get; } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/INamespace.cs b/ICSharpCode.Decompiler/TypeSystem/INamespace.cs new file mode 100644 index 000000000..213f2f87b --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/INamespace.cs @@ -0,0 +1,88 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Represents a resolved namespace. + /// + public interface INamespace : ISymbol, ICompilationProvider + { + // No pointer back to unresolved namespace: + // multiple unresolved namespaces (from different assemblies) get + // merged into one INamespace. + + /// + /// Gets the extern alias for this namespace. + /// Returns an empty string for normal namespaces. + /// + string ExternAlias { get; } + + /// + /// Gets the full name of this namespace. (e.g. "System.Collections") + /// + string FullName { get; } + + /// + /// Gets the short name of this namespace (e.g. "Collections"). + /// + new string Name { get; } + + /// + /// Gets the parent namespace. + /// Returns null if this is the root namespace. + /// + INamespace ParentNamespace { get; } + + /// + /// Gets the child namespaces in this namespace. + /// + IEnumerable ChildNamespaces { get; } + + /// + /// Gets the types in this namespace. + /// + IEnumerable Types { get; } + + /// + /// Gets the assemblies that contribute types to this namespace (or to child namespaces). + /// + IEnumerable ContributingAssemblies { get; } + + /// + /// Gets a direct child namespace by its short name. + /// Returns null when the namespace cannot be found. + /// + /// + /// This method uses the compilation's current string comparer. + /// + INamespace GetChildNamespace(string name); + + /// + /// Gets the type with the specified short name and type parameter count. + /// Returns null if the type cannot be found. + /// + /// + /// This method uses the compilation's current string comparer. + /// + ITypeDefinition GetTypeDefinition(string name, int typeParameterCount); + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/IParameter.cs b/ICSharpCode.Decompiler/TypeSystem/IParameter.cs new file mode 100644 index 000000000..74f23c691 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/IParameter.cs @@ -0,0 +1,104 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Diagnostics.Contracts; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + public interface IUnresolvedParameter + { + /// + /// Gets the name of the variable. + /// + string Name { get; } + + /// + /// Gets the declaration region of the variable. + /// + DomRegion Region { get; } + + /// + /// Gets the type of the variable. + /// + ITypeReference Type { get; } + + /// + /// Gets the list of attributes. + /// + IList Attributes { get; } + + /// + /// Gets whether this parameter is a C# 'ref' parameter. + /// + bool IsRef { get; } + + /// + /// Gets whether this parameter is a C# 'out' parameter. + /// + bool IsOut { get; } + + /// + /// Gets whether this parameter is a C# 'params' parameter. + /// + bool IsParams { get; } + + /// + /// Gets whether this parameter is optional. + /// + bool IsOptional { get; } + + IParameter CreateResolvedParameter(ITypeResolveContext context); + } + + public interface IParameter : IVariable + { + /// + /// Gets the list of attributes. + /// + IList Attributes { get; } + + /// + /// Gets whether this parameter is a C# 'ref' parameter. + /// + bool IsRef { get; } + + /// + /// Gets whether this parameter is a C# 'out' parameter. + /// + bool IsOut { get; } + + /// + /// Gets whether this parameter is a C# 'params' parameter. + /// + bool IsParams { get; } + + /// + /// Gets whether this parameter is optional. + /// The default value is given by the property. + /// + bool IsOptional { get; } + + /// + /// Gets the owner of this parameter. + /// May return null; for example when parameters belong to lambdas or anonymous methods. + /// + IParameterizedMember Owner { get; } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/IParameterizedMember.cs b/ICSharpCode.Decompiler/TypeSystem/IParameterizedMember.cs new file mode 100644 index 000000000..e76f10608 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/IParameterizedMember.cs @@ -0,0 +1,40 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Diagnostics.Contracts; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Represents a method or property. + /// + public interface IUnresolvedParameterizedMember : IUnresolvedMember + { + IList Parameters { get; } + } + + /// + /// Represents a method or property. + /// + public interface IParameterizedMember : IMember + { + IList Parameters { get; } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/IProjectContent.cs b/ICSharpCode.Decompiler/TypeSystem/IProjectContent.cs new file mode 100644 index 000000000..ff6a39c35 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/IProjectContent.cs @@ -0,0 +1,159 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Diagnostics.Contracts; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Represents an assembly consisting of source code (parsed files). + /// + public interface IProjectContent : IUnresolvedAssembly + { + /// + /// Gets the path to the project file (e.g. .csproj). + /// + string ProjectFileName { get; } + + /// + /// Gets a parsed file by its file name. + /// + IUnresolvedFile GetFile(string fileName); + + /// + /// Gets the list of all files in the project content. + /// + IEnumerable Files { get; } + + /// + /// Gets the referenced assemblies. + /// + IEnumerable AssemblyReferences { get; } + + /// + /// Gets the compiler settings object. + /// The concrete type of the settings object depends on the programming language used to implement this project. + /// + object CompilerSettings { get; } + + /// + /// Creates a new that allows resolving within this project. + /// + /// + /// This method does not support s. When dealing with a solution + /// containing multiple projects, consider using instead. + /// + ICompilation CreateCompilation(); + + /// + /// Creates a new that allows resolving within this project. + /// + /// The parent solution snapshot to use for the compilation. + /// + /// This method is intended to be called by ISolutionSnapshot implementations. Other code should + /// call instead. + /// This method always creates a new compilation, even if the solution snapshot already contains + /// one for this project. + /// + ICompilation CreateCompilation(ISolutionSnapshot solutionSnapshot); + + /// + /// Changes the assembly name of this project content. + /// + IProjectContent SetAssemblyName(string newAssemblyName); + + /// + /// Changes the project file name of this project content. + /// + IProjectContent SetProjectFileName(string newProjectFileName); + + /// + /// Changes the path to the assembly location (the output path where the project compiles to). + /// + IProjectContent SetLocation(string newLocation); + + /// + /// Add assembly references to this project content. + /// + IProjectContent AddAssemblyReferences(IEnumerable references); + + /// + /// Add assembly references to this project content. + /// + IProjectContent AddAssemblyReferences(params IAssemblyReference[] references); + + /// + /// Removes assembly references from this project content. + /// + IProjectContent RemoveAssemblyReferences(IEnumerable references); + + /// + /// Removes assembly references from this project content. + /// + IProjectContent RemoveAssemblyReferences(params IAssemblyReference[] references); + + /// + /// Adds the specified files to the project content. + /// If a file with the same name already exists, updated the existing file. + /// + /// + /// You can create an unresolved file by calling ToTypeSystem() on a syntax tree. + /// + IProjectContent AddOrUpdateFiles(IEnumerable newFiles); + + /// + /// Adds the specified files to the project content. + /// If a file with the same name already exists, this method updates the existing file. + /// + /// + /// You can create an unresolved file by calling ToTypeSystem() on a syntax tree. + /// + IProjectContent AddOrUpdateFiles(params IUnresolvedFile[] newFiles); + + /// + /// Removes the files with the specified names. + /// + IProjectContent RemoveFiles(IEnumerable fileNames); + + /// + /// Removes the files with the specified names. + /// + IProjectContent RemoveFiles(params string[] fileNames); + + /// + /// Removes types and attributes from oldFile from the project, and adds those from newFile. + /// + [Obsolete("Use RemoveFiles()/AddOrUpdateFiles() instead")] + IProjectContent UpdateProjectContent(IUnresolvedFile oldFile, IUnresolvedFile newFile); + + /// + /// Removes types and attributes from oldFiles from the project, and adds those from newFiles. + /// + [Obsolete("Use RemoveFiles()/AddOrUpdateFiles() instead")] + IProjectContent UpdateProjectContent(IEnumerable oldFiles, IEnumerable newFiles); + + /// + /// Sets the compiler settings object. + /// The concrete type of the settings object depends on the programming language used to implement this project. + /// Using the incorrect type of settings object results in an . + /// + IProjectContent SetCompilerSettings(object compilerSettings); + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/IProperty.cs b/ICSharpCode.Decompiler/TypeSystem/IProperty.cs new file mode 100644 index 000000000..df9d613e6 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/IProperty.cs @@ -0,0 +1,62 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Represents a property or indexer. + /// + public interface IUnresolvedProperty : IUnresolvedParameterizedMember + { + bool CanGet { get; } + bool CanSet { get; } + + IUnresolvedMethod Getter { get; } + IUnresolvedMethod Setter { get; } + + bool IsIndexer { get; } + + /// + /// Resolves the member. + /// + /// + /// Context for looking up the member. The context must specify the current assembly. + /// A that specifies the current assembly is sufficient. + /// + /// + /// Returns the resolved member, or null if the member could not be found. + /// + new IProperty Resolve(ITypeResolveContext context); + } + + /// + /// Represents a property or indexer. + /// + public interface IProperty : IParameterizedMember + { + bool CanGet { get; } + bool CanSet { get; } + + IMethod Getter { get; } + IMethod Setter { get; } + + bool IsIndexer { get; } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/ISolutionSnapshot.cs b/ICSharpCode.Decompiler/TypeSystem/ISolutionSnapshot.cs new file mode 100644 index 000000000..de302731d --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/ISolutionSnapshot.cs @@ -0,0 +1,43 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Represents a snapshot of the whole solution (multiple compilations). + /// + public interface ISolutionSnapshot + { + /// + /// Gets the project content with the specified file name. + /// Returns null if no such project exists in the solution. + /// + /// + /// This method is used by the class. + /// + IProjectContent GetProjectContent(string projectFileName); + + /// + /// Gets the compilation for the specified project. + /// The project must be a part of the solution (passed to the solution snapshot's constructor). + /// + ICompilation GetCompilation(IProjectContent project); + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/ISupportsInterning.cs b/ICSharpCode.Decompiler/TypeSystem/ISupportsInterning.cs new file mode 100644 index 000000000..5188bffe5 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/ISupportsInterning.cs @@ -0,0 +1,39 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Interface for TypeSystem objects that support interning. + /// See for more information. + /// + public interface ISupportsInterning + { + /// + /// Gets a hash code for interning. + /// + int GetHashCodeForInterning(); + + /// + /// Equality test for interning. + /// + bool EqualsForInterning(ISupportsInterning other); + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/ISymbol.cs b/ICSharpCode.Decompiler/TypeSystem/ISymbol.cs new file mode 100644 index 000000000..495c932fd --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/ISymbol.cs @@ -0,0 +1,100 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + public enum SymbolKind : byte + { + None, + /// + TypeDefinition, + /// + Field, + /// + /// The symbol is a property, but not an indexer. + /// + /// + Property, + /// + /// The symbol is an indexer, not a regular property. + /// + /// + Indexer, + /// + Event, + /// + /// The symbol is a method which is not an operator/constructor/destructor or accessor. + /// + /// + Method, + /// + /// The symbol is a user-defined operator. + /// + /// + Operator, + /// + Constructor, + /// + Destructor, + /// + /// The accessor method for a property getter/setter or event add/remove. + /// + /// + Accessor, + /// + Namespace, + /// + /// The symbol is a variable, but not a parameter. + /// + /// + Variable, + /// + Parameter, + /// + TypeParameter, + } + + /// + /// Interface for type system symbols. + /// + public interface ISymbol + { + /// + /// This property returns an enum specifying which kind of symbol this is + /// (which derived interfaces of ISymbol are implemented) + /// + SymbolKind SymbolKind { get; } + + /// + /// Gets the short name of the symbol. + /// + string Name { get; } + + /// + /// Creates a symbol reference that can be used to rediscover this symbol in another compilation. + /// + ISymbolReference ToReference(); + } + + public interface ISymbolReference + { + ISymbol Resolve(ITypeResolveContext context); + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/IType.cs b/ICSharpCode.Decompiler/TypeSystem/IType.cs new file mode 100644 index 000000000..2a85f2b9a --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/IType.cs @@ -0,0 +1,350 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// This interface represents a resolved type in the type system. + /// + /// + /// + /// A type is potentially + /// - a type definition (, i.e. a class, struct, interface, delegate, or built-in primitive type) + /// - a parameterized type (, e.g. List<int>) + /// - a type parameter (, e.g. T) + /// - an array () + /// - a pointer () + /// - a managed reference () + /// - one of the special types (, , + /// , ) + /// + /// The property can be used to switch on the kind of a type. + /// + /// + /// IType uses the null object pattern: serves as the null object. + /// Methods or properties returning IType never return null unless documented otherwise. + /// + /// + /// Types should be compared for equality using the method. + /// Identical types do not necessarily use the same object reference. + /// + /// + public interface IType : INamedElement, IEquatable + { + /// + /// Gets the type kind. + /// + TypeKind Kind { get; } + + /// + /// Gets whether the type is a reference type or value type. + /// + /// + /// true, if the type is a reference type. + /// false, if the type is a value type. + /// null, if the type is not known (e.g. unconstrained generic type parameter or type not found) + /// + bool? IsReferenceType { get; } + + /// + /// Gets the underlying type definition. + /// Can return null for types which do not have a type definition (for example arrays, pointers, type parameters). + /// + ITypeDefinition GetDefinition(); + + /// + /// Gets the parent type, if this is a nested type. + /// Returns null for top-level types. + /// + IType DeclaringType { get; } + + /// + /// Gets the number of type parameters. + /// + int TypeParameterCount { get; } + + /// + /// Gets the type arguments passed to this type. + /// If this type is a generic type definition that is not parameterized, this property returns the type parameters, + /// as if the type was parameterized with its own type arguments (class C<T> { C<T> field; }). + /// + /// NOTE: The type will change to IReadOnlyList<IType> in future versions. + /// + IList TypeArguments { get; } + + /// + /// If true the type represents an instance of a generic type. + /// + bool IsParameterized { get; } + + /// + /// Calls ITypeVisitor.Visit for this type. + /// + /// The return value of the ITypeVisitor.Visit call + IType AcceptVisitor(TypeVisitor visitor); + + /// + /// Calls ITypeVisitor.Visit for all children of this type, and reconstructs this type with the children based + /// on the return values of the visit calls. + /// + /// A copy of this type, with all children replaced by the return value of the corresponding visitor call. + /// If the visitor returned the original types for all children (or if there are no children), returns this. + /// + IType VisitChildren(TypeVisitor visitor); + + /// + /// Gets the direct base types. + /// + /// Returns the direct base types including interfaces + IEnumerable DirectBaseTypes { get; } + + /// + /// Creates a type reference that can be used to look up a type equivalent to this type in another compilation. + /// + /// + /// If this type contains open generics, the resulting type reference will need to be looked up in an appropriate generic context. + /// Otherwise, the main resolve context of a compilation is sufficient. + /// + ITypeReference ToTypeReference(); + + /// + /// Gets a type visitor that performs the substitution of class type parameters with the type arguments + /// of this parameterized type. + /// Returns TypeParameterSubstitution.Identity if the type is not parametrized. + /// + TypeParameterSubstitution GetSubstitution(); + + /// + /// Gets a type visitor that performs the substitution of class type parameters with the type arguments + /// of this parameterized type, + /// and also substitutes method type parameters with the specified method type arguments. + /// Returns TypeParameterSubstitution.Identity if the type is not parametrized. + /// + TypeParameterSubstitution GetSubstitution(IList methodTypeArguments); + + + /// + /// Gets inner classes (including inherited inner classes). + /// + /// The filter used to select which types to return. + /// The filter is tested on the original type definitions (before parameterization). + /// Specified additional options for the GetMembers() operation. + /// + /// + /// If the nested type is generic, this method will return a parameterized type, + /// where the additional type parameters are set to . + /// + /// + /// Type parameters belonging to the outer class will have the value copied from the outer type + /// if it is a parameterized type. Otherwise, those existing type parameters will be self-parameterized, + /// and thus 'leaked' to the caller in the same way the GetMembers() method does not specialize members + /// from an and 'leaks' type parameters in member signatures. + /// + /// + /// + /// + /// class Base<T> { + /// class Nested<X> {} + /// } + /// class Derived<A, B> : Base<B> {} + /// + /// Derived[string,int].GetNestedTypes() = { Base`1+Nested`1[int, unbound] } + /// Derived.GetNestedTypes() = { Base`1+Nested`1[`1, unbound] } + /// Base[`1].GetNestedTypes() = { Base`1+Nested`1[`1, unbound] } + /// Base.GetNestedTypes() = { Base`1+Nested`1[`0, unbound] } + /// + /// + IEnumerable GetNestedTypes(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None); + + // Note that we cannot 'leak' the additional type parameter as we leak the normal type parameters, because + // the index might collide. For example, + // class Base { class Nested {} } + // class Derived : Base { } + // + // Derived.GetNestedTypes() = Base+Nested + // Derived.GetNestedTypes() = Base+Nested<`1, > + // Here `1 refers to B, and there's no way to return X as it would collide with B. + + /// + /// Gets inner classes (including inherited inner classes) + /// that have typeArguments.Count additional type parameters. + /// + /// The type arguments passed to the inner class + /// The filter used to select which types to return. + /// The filter is tested on the original type definitions (before parameterization). + /// Specified additional options for the GetMembers() operation. + /// + /// Type parameters belonging to the outer class will have the value copied from the outer type + /// if it is a parameterized type. Otherwise, those existing type parameters will be self-parameterized, + /// and thus 'leaked' to the caller in the same way the GetMembers() method does not specialize members + /// from an and 'leaks' type parameters in member signatures. + /// + IEnumerable GetNestedTypes(IList typeArguments, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None); + + /// + /// Gets all instance constructors for this type. + /// + /// The filter used to select which constructors to return. + /// The filter is tested on the original method definitions (before specialization). + /// Specified additional options for the GetMembers() operation. + /// + /// The result does not include static constructors. + /// Constructors in base classes are not returned by default, as GetMemberOptions.IgnoreInheritedMembers is the default value. + /// + /// For methods on parameterized types, type substitution will be performed on the method signature, + /// and the appropriate will be returned. + /// + /// + IEnumerable GetConstructors(Predicate filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers); + + /// + /// Gets all methods that can be called on this type. + /// + /// The filter used to select which methods to return. + /// The filter is tested on the original method definitions (before specialization). + /// Specified additional options for the GetMembers() operation. + /// + /// + /// The result does not include constructors or accessors. + /// + /// + /// For methods on parameterized types, type substitution will be performed on the method signature, + /// and the appropriate will be returned. + /// + /// + /// If the method being returned is generic, and this type is a parameterized type where the type + /// arguments involve another method's type parameters, the resulting specialized signature + /// will be ambiguous as to which method a type parameter belongs to. + /// For example, "List[[``0]].GetMethods()" will return "ConvertAll(Converter`2[[``0, ``0]])". + /// + /// If possible, use the other GetMethods() overload to supply type arguments to the method, + /// so that both class and method type parameter can be substituted at the same time, so that + /// the ambiguity can be avoided. + /// + /// + IEnumerable GetMethods(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None); + + /// + /// Gets all generic methods that can be called on this type with the specified type arguments. + /// + /// The type arguments used for the method call. + /// The filter used to select which methods to return. + /// The filter is tested on the original method definitions (before specialization). + /// Specified additional options for the GetMembers() operation. + /// + /// The result does not include constructors or accessors. + /// + /// Type substitution will be performed on the method signature, creating a + /// with the specified type arguments. + /// + /// + /// When the list of type arguments is empty, this method acts like the GetMethods() overload without + /// the type arguments parameter - that is, it also returns generic methods, + /// and the other overload's remarks about ambiguous signatures apply here as well. + /// + /// + IEnumerable GetMethods(IList typeArguments, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None); + + /// + /// Gets all properties that can be called on this type. + /// + /// The filter used to select which properties to return. + /// The filter is tested on the original property definitions (before specialization). + /// Specified additional options for the GetMembers() operation. + /// + /// For properties on parameterized types, type substitution will be performed on the property signature, + /// and the appropriate will be returned. + /// + IEnumerable GetProperties(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None); + + /// + /// Gets all fields that can be accessed on this type. + /// + /// The filter used to select which constructors to return. + /// The filter is tested on the original field definitions (before specialization). + /// Specified additional options for the GetMembers() operation. + /// + /// For fields on parameterized types, type substitution will be performed on the field's return type, + /// and the appropriate will be returned. + /// + IEnumerable GetFields(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None); + + /// + /// Gets all events that can be accessed on this type. + /// + /// The filter used to select which events to return. + /// The filter is tested on the original event definitions (before specialization). + /// Specified additional options for the GetMembers() operation. + /// + /// For fields on parameterized types, type substitution will be performed on the event's return type, + /// and the appropriate will be returned. + /// + IEnumerable GetEvents(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None); + + /// + /// Gets all members that can be called on this type. + /// + /// The filter used to select which members to return. + /// The filter is tested on the original member definitions (before specialization). + /// Specified additional options for the GetMembers() operation. + /// + /// + /// The resulting list is the union of GetFields(), GetProperties(), GetMethods() and GetEvents(). + /// It does not include constructors. + /// For parameterized types, type substitution will be performed. + /// + /// + /// For generic methods, the remarks about ambiguous signatures from the + /// method apply here as well. + /// + /// + IEnumerable GetMembers(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None); + + /// + /// Gets all accessors belonging to properties or events on this type. + /// + /// The filter used to select which members to return. + /// The filter is tested on the original member definitions (before specialization). + /// Specified additional options for the GetMembers() operation. + /// + /// Accessors are not returned by GetMembers() or GetMethods(). + /// + IEnumerable GetAccessors(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None); + } + + [Flags] + public enum GetMemberOptions + { + /// + /// No options specified - this is the default. + /// Members will be specialized, and inherited members will be included. + /// + None = 0x00, + /// + /// Do not specialize the returned members - directly return the definitions. + /// + ReturnMemberDefinitions = 0x01, + /// + /// Do not list inherited members - only list members defined directly on this type. + /// + IgnoreInheritedMembers = 0x02 + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/ITypeDefinition.cs b/ICSharpCode.Decompiler/TypeSystem/ITypeDefinition.cs new file mode 100644 index 000000000..9a3b0b63a --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/ITypeDefinition.cs @@ -0,0 +1,170 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Diagnostics.Contracts; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Represents an unresolved class, enum, interface, struct, delegate or VB module. + /// For partial classes, an unresolved type definition represents only a single part. + /// + public interface IUnresolvedTypeDefinition : ITypeReference, IUnresolvedEntity + { + TypeKind Kind { get; } + + FullTypeName FullTypeName { get; } + IList BaseTypes { get; } + IList TypeParameters { get; } + + IList NestedTypes { get; } + IList Members { get; } + + IEnumerable Methods { get; } + IEnumerable Properties { get; } + IEnumerable Fields { get; } + IEnumerable Events { get; } + + /// + /// Gets whether the type definition contains extension methods. + /// Returns null when the type definition needs to be resolved in order to determine whether + /// methods are extension methods. + /// + bool? HasExtensionMethods { get; } + + /// + /// Gets whether the partial modifier is set on this part of the type definition. + /// + bool IsPartial { get; } + + /// + /// Gets whether this unresolved type definition causes the addition of a default constructor + /// if no other constructor is present. + /// + bool AddDefaultConstructorIfRequired { get; } + + /// + /// Looks up the resolved type definition from the corresponding to this unresolved + /// type definition. + /// + /// + /// Context for looking up the type. The context must specify the current assembly. + /// A that specifies the current assembly is sufficient. + /// + /// + /// Returns the resolved type definition. + /// In case of an error, returns an instance. + /// Never returns null. + /// + new IType Resolve(ITypeResolveContext context); + + /// + /// This method is used to add language-specific elements like the C# UsingScope + /// to the type resolve context. + /// + /// The parent context (e.g. the parent assembly), + /// including the parent type definition for inner classes. + /// + /// The parent context, modified to include language-specific elements (e.g. using scope) + /// associated with this type definition. + /// + /// + /// Use unresolvedTypeDef.CreateResolveContext(parentContext).WithTypeDefinition(typeDef) to + /// create the context for use within the type definition. + /// + ITypeResolveContext CreateResolveContext(ITypeResolveContext parentContext); + } + + /// + /// Represents a class, enum, interface, struct, delegate or VB module. + /// For partial classes, this represents the whole class. + /// + public interface ITypeDefinition : IType, IEntity + { + /// + /// Returns all parts that contribute to this type definition. + /// Non-partial classes have a single part that represents the whole class. + /// + IList Parts { get; } + + IList TypeParameters { get; } + + IList NestedTypes { get; } + IList Members { get; } + + IEnumerable Fields { get; } + IEnumerable Methods { get; } + IEnumerable Properties { get; } + IEnumerable Events { get; } + + /// + /// Gets the known type code for this type definition. + /// + KnownTypeCode KnownTypeCode { get; } + + /// + /// For enums: returns the underlying primitive type. + /// For all other types: returns . + /// + IType EnumUnderlyingType { get; } + + /// + /// Gets the full name of this type. + /// + FullTypeName FullTypeName { get; } + + /// + /// Gets/Sets the declaring type (incl. type arguments, if any). + /// This property will return null for top-level types. + /// + new IType DeclaringType { get; } // solves ambiguity between IType.DeclaringType and IEntity.DeclaringType + + /// + /// Gets whether this type contains extension methods. + /// + /// This property is used to speed up the search for extension methods. + bool HasExtensionMethods { get; } + + /// + /// Gets whether this type definition is made up of one or more partial classes. + /// + bool IsPartial { get; } + + /// + /// Determines how this type is implementing the specified interface member. + /// + /// + /// The method on this type that implements the interface member; + /// or null if the type does not implement the interface. + /// + IMember GetInterfaceImplementation(IMember interfaceMember); + + /// + /// Determines how this type is implementing the specified interface members. + /// + /// + /// For each interface member, this method returns the class member + /// that implements the interface member. + /// For interface members that are missing an implementation, the + /// result collection will contain a null element. + /// + IList GetInterfaceImplementation(IList interfaceMembers); + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/ITypeParameter.cs b/ICSharpCode.Decompiler/TypeSystem/ITypeParameter.cs new file mode 100644 index 000000000..e74af0557 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/ITypeParameter.cs @@ -0,0 +1,151 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Diagnostics.Contracts; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Type parameter of a generic class/method. + /// + public interface IUnresolvedTypeParameter : INamedElement + { + /// + /// Get the type of this type parameter's owner. + /// + /// SymbolKind.TypeDefinition or SymbolKind.Method + SymbolKind OwnerType { get; } + + /// + /// Gets the index of the type parameter in the type parameter list of the owning method/class. + /// + int Index { get; } + + /// + /// Gets the list of attributes declared on this type parameter. + /// + IList Attributes { get; } + + /// + /// Gets the variance of this type parameter. + /// + VarianceModifier Variance { get; } + + /// + /// Gets the region where the type parameter is defined. + /// + DomRegion Region { get; } + + ITypeParameter CreateResolvedTypeParameter(ITypeResolveContext context); + } + + /// + /// Type parameter of a generic class/method. + /// + public interface ITypeParameter : IType, ISymbol + { + /// + /// Get the type of this type parameter's owner. + /// + /// SymbolKind.TypeDefinition or SymbolKind.Method + SymbolKind OwnerType { get; } + + /// + /// Gets the owning method/class. + /// This property may return null (for example for the dummy type parameters used by ). + /// + /// + /// For "class Outer<T> { class Inner {} }", + /// inner.TypeParameters[0].Owner will be the outer class, because the same + /// ITypeParameter instance is used both on Outer`1 and Outer`1+Inner. + /// + IEntity Owner { get; } + + /// + /// Gets the index of the type parameter in the type parameter list of the owning method/class. + /// + int Index { get; } + + /// + /// Gets the name of the type parameter. + /// + new string Name { get; } + + /// + /// Gets the list of attributes declared on this type parameter. + /// + IList Attributes { get; } + + /// + /// Gets the variance of this type parameter. + /// + VarianceModifier Variance { get; } + + /// + /// Gets the region where the type parameter is defined. + /// + DomRegion Region { get; } + + /// + /// Gets the effective base class of this type parameter. + /// + IType EffectiveBaseClass { get; } + + /// + /// Gets the effective interface set of this type parameter. + /// + ICollection EffectiveInterfaceSet { get; } + + /// + /// Gets if the type parameter has the 'new()' constraint. + /// + bool HasDefaultConstructorConstraint { get; } + + /// + /// Gets if the type parameter has the 'class' constraint. + /// + bool HasReferenceTypeConstraint { get; } + + /// + /// Gets if the type parameter has the 'struct' constraint. + /// + bool HasValueTypeConstraint { get; } + } + + /// + /// Represents the variance of a type parameter. + /// + public enum VarianceModifier : byte + { + /// + /// The type parameter is not variant. + /// + Invariant, + /// + /// The type parameter is covariant (used in output position). + /// + Covariant, + /// + /// The type parameter is contravariant (used in input position). + /// + Contravariant + }; +} diff --git a/ICSharpCode.Decompiler/TypeSystem/ITypeReference.cs b/ICSharpCode.Decompiler/TypeSystem/ITypeReference.cs new file mode 100644 index 000000000..a5186820a --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/ITypeReference.cs @@ -0,0 +1,73 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Represents a reference to a type. + /// Must be resolved before it can be used as type. + /// + public interface ITypeReference + { + // Keep this interface simple: I decided against having GetMethods/GetEvents etc. here, + // so that the Resolve step is never hidden from the consumer. + + // I decided against implementing IFreezable here: IUnresolvedTypeDefinition can be used as ITypeReference, + // but when freezing the reference, one wouldn't expect the definition to freeze. + + /// + /// Resolves this type reference. + /// + /// + /// Context to use for resolving this type reference. + /// Which kind of context is required depends on the which kind of type reference this is; + /// please consult the documentation of the method that was used to create this type reference, + /// or that of the class implementing this method. + /// + /// + /// Returns the resolved type. + /// In case of an error, returns an unknown type (). + /// Never returns null. + /// + IType Resolve(ITypeResolveContext context); + } + + public interface ITypeResolveContext : ICompilationProvider + { + /// + /// Gets the current assembly. + /// This property may return null if this context does not specify any assembly. + /// + IAssembly CurrentAssembly { get; } + + /// + /// Gets the current type definition. + /// + ITypeDefinition CurrentTypeDefinition { get ;} + + /// + /// Gets the current member. + /// + IMember CurrentMember { get; } + + ITypeResolveContext WithCurrentTypeDefinition(ITypeDefinition typeDefinition); + ITypeResolveContext WithCurrentMember(IMember member); + } +} \ No newline at end of file diff --git a/ICSharpCode.Decompiler/TypeSystem/IUnresolvedFile.cs b/ICSharpCode.Decompiler/TypeSystem/IUnresolvedFile.cs new file mode 100644 index 000000000..7c7918c06 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/IUnresolvedFile.cs @@ -0,0 +1,80 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + [Obsolete("IParsedFile was renamed to IUnresolvedFile", true)] + public interface IParsedFile {} + + /// + /// Represents a single file that was parsed. + /// + public interface IUnresolvedFile + { + /// + /// Returns the full path of the file. + /// + string FileName { get; } + + /// + /// Gets the time when the file was last written. + /// + DateTime? LastWriteTime { get; set; } + + /// + /// Gets all top-level type definitions. + /// + IList TopLevelTypeDefinitions { get; } + + /// + /// Gets all assembly attributes that are defined in this file. + /// + IList AssemblyAttributes { get; } + + /// + /// Gets all module attributes that are defined in this file. + /// + IList ModuleAttributes { get; } + + /// + /// Gets the top-level type defined at the specified location. + /// Returns null if no type is defined at that location. + /// + IUnresolvedTypeDefinition GetTopLevelTypeDefinition(TextLocation location); + + /// + /// Gets the type (potentially a nested type) defined at the specified location. + /// Returns null if no type is defined at that location. + /// + IUnresolvedTypeDefinition GetInnermostTypeDefinition(TextLocation location); + + /// + /// Gets the member defined at the specified location. + /// Returns null if no member is defined at that location. + /// + IUnresolvedMember GetMember(TextLocation location); + + /// + /// Gets the parser errors. + /// + IList Errors { get; } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/IVariable.cs b/ICSharpCode.Decompiler/TypeSystem/IVariable.cs new file mode 100644 index 000000000..253fe99a5 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/IVariable.cs @@ -0,0 +1,54 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Represents a variable (name/type pair). + /// + public interface IVariable : ISymbol + { + /// + /// Gets the name of the variable. + /// + new string Name { get; } + + /// + /// Gets the declaration region of the variable. + /// + DomRegion Region { get; } + + /// + /// Gets the type of the variable. + /// + IType Type { get; } + + /// + /// Gets whether this variable is a constant (C#-like const). + /// + bool IsConst { get; } + + /// + /// If this field is a constant, retrieves the value. + /// For parameters, this is the default value. + /// + object ConstantValue { get; } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractFreezable.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractFreezable.cs new file mode 100644 index 000000000..1a3dbd3a3 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractFreezable.cs @@ -0,0 +1,110 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Collections.ObjectModel; +using System.Linq; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + public static class FreezableHelper + { + public static void ThrowIfFrozen(IFreezable freezable) + { + if (freezable.IsFrozen) + throw new InvalidOperationException("Cannot mutate frozen " + freezable.GetType().Name); + } + + public static IList FreezeListAndElements(IList list) + { + if (list != null) { + foreach (T item in list) + Freeze(item); + } + return FreezeList(list); + } + + public static IList FreezeList(IList list) + { + if (list == null || list.Count == 0) + return EmptyList.Instance; + if (list.IsReadOnly) { + // If the list is already read-only, return it directly. + // This is important, otherwise we might undo the effects of interning. + return list; + } else { + return new ReadOnlyCollection(list.ToArray()); + } + } + + public static void Freeze(object item) + { + IFreezable f = item as IFreezable; + if (f != null) + f.Freeze(); + } + + public static T FreezeAndReturn(T item) where T : IFreezable + { + item.Freeze(); + return item; + } + + /// + /// If the item is not frozen, this method creates and returns a frozen clone. + /// If the item is already frozen, it is returned without creating a clone. + /// + public static T GetFrozenClone(T item) where T : IFreezable, ICloneable + { + if (!item.IsFrozen) { + item = (T)item.Clone(); + item.Freeze(); + } + return item; + } + } + + [Serializable] + public abstract class AbstractFreezable : IFreezable + { + bool isFrozen; + + /// + /// Gets if this instance is frozen. Frozen instances are immutable and thus thread-safe. + /// + public bool IsFrozen { + get { return isFrozen; } + } + + /// + /// Freezes this instance. + /// + public void Freeze() + { + if (!isFrozen) { + FreezeInternal(); + isFrozen = true; + } + } + + protected virtual void FreezeInternal() + { + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractResolvedEntity.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractResolvedEntity.cs new file mode 100644 index 000000000..1a3fe19bd --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractResolvedEntity.cs @@ -0,0 +1,124 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Documentation; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Implementation of that resolves an unresolved entity. + /// + public abstract class AbstractResolvedEntity : IEntity + { + protected readonly IUnresolvedEntity unresolved; + protected readonly ITypeResolveContext parentContext; + + protected AbstractResolvedEntity(IUnresolvedEntity unresolved, ITypeResolveContext parentContext) + { + if (unresolved == null) + throw new ArgumentNullException("unresolved"); + if (parentContext == null) + throw new ArgumentNullException("parentContext"); + this.unresolved = unresolved; + this.parentContext = parentContext; + this.Attributes = unresolved.Attributes.CreateResolvedAttributes(parentContext); + } + + public SymbolKind SymbolKind { + get { return unresolved.SymbolKind; } + } + + [Obsolete("Use the SymbolKind property instead.")] + public EntityType EntityType { + get { return (EntityType)unresolved.SymbolKind; } + } + + public DomRegion Region { + get { return unresolved.Region; } + } + + public DomRegion BodyRegion { + get { return unresolved.BodyRegion; } + } + + public ITypeDefinition DeclaringTypeDefinition { + get { return parentContext.CurrentTypeDefinition; } + } + + public virtual IType DeclaringType { + get { return parentContext.CurrentTypeDefinition; } + } + + public IAssembly ParentAssembly { + get { return parentContext.CurrentAssembly; } + } + + public IList Attributes { get; protected set; } + + public virtual DocumentationComment Documentation { + get { + IDocumentationProvider provider = FindDocumentation(parentContext); + if (provider != null) + return provider.GetDocumentation(this); + else + return null; + } + } + + internal static IDocumentationProvider FindDocumentation(ITypeResolveContext context) + { + IAssembly asm = context.CurrentAssembly; + if (asm != null) + return asm.UnresolvedAssembly as IDocumentationProvider; + else + return null; + } + + public abstract ISymbolReference ToReference(); + + public bool IsStatic { get { return unresolved.IsStatic; } } + public bool IsAbstract { get { return unresolved.IsAbstract; } } + public bool IsSealed { get { return unresolved.IsSealed; } } + public bool IsShadowing { get { return unresolved.IsShadowing; } } + public bool IsSynthetic { get { return unresolved.IsSynthetic; } } + + public ICompilation Compilation { + get { return parentContext.Compilation; } + } + + public string FullName { get { return unresolved.FullName; } } + public string Name { get { return unresolved.Name; } } + public string ReflectionName { get { return unresolved.ReflectionName; } } + public string Namespace { get { return unresolved.Namespace; } } + + public virtual Accessibility Accessibility { get { return unresolved.Accessibility; } } + public bool IsPrivate { get { return Accessibility == Accessibility.Private; } } + public bool IsPublic { get { return Accessibility == Accessibility.Public; } } + public bool IsProtected { get { return Accessibility == Accessibility.Protected; } } + public bool IsInternal { get { return Accessibility == Accessibility.Internal; } } + public bool IsProtectedOrInternal { get { return Accessibility == Accessibility.ProtectedOrInternal; } } + public bool IsProtectedAndInternal { get { return Accessibility == Accessibility.ProtectedAndInternal; } } + + public override string ToString() + { + return "[" + this.SymbolKind.ToString() + " " + this.ReflectionName + "]"; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractResolvedMember.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractResolvedMember.cs new file mode 100644 index 000000000..e64f2aa5a --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractResolvedMember.cs @@ -0,0 +1,168 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; +using ICSharpCode.NRefactory.Documentation; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Implementation of that resolves an unresolved member. + /// + public abstract class AbstractResolvedMember : AbstractResolvedEntity, IMember + { + protected new readonly IUnresolvedMember unresolved; + protected readonly ITypeResolveContext context; + volatile IType returnType; + IList implementedInterfaceMembers; + + protected AbstractResolvedMember(IUnresolvedMember unresolved, ITypeResolveContext parentContext) + : base(unresolved, parentContext) + { + this.unresolved = unresolved; + this.context = parentContext.WithCurrentMember(this); + } + + IMember IMember.MemberDefinition { + get { return this; } + } + + public IType ReturnType { + get { + return this.returnType ?? (this.returnType = unresolved.ReturnType.Resolve(context)); + } + } + + public IUnresolvedMember UnresolvedMember { + get { return unresolved; } + } + + public IList ImplementedInterfaceMembers { + get { + IList result = LazyInit.VolatileRead(ref this.implementedInterfaceMembers); + if (result != null) { + return result; + } else { + return LazyInit.GetOrSet(ref implementedInterfaceMembers, FindImplementedInterfaceMembers()); + } + } + } + + IList FindImplementedInterfaceMembers() + { + if (unresolved.IsExplicitInterfaceImplementation) { + List result = new List(); + foreach (var memberReference in unresolved.ExplicitInterfaceImplementations) { + IMember member = memberReference.Resolve(context); + if (member != null) + result.Add(member); + } + return result.ToArray(); + } else if (unresolved.IsStatic || !unresolved.IsPublic || DeclaringTypeDefinition == null || DeclaringTypeDefinition.Kind == TypeKind.Interface) { + return EmptyList.Instance; + } else { + // TODO: implement interface member mappings correctly + var result = InheritanceHelper.GetBaseMembers(this, true) + .Where(m => m.DeclaringTypeDefinition != null && m.DeclaringTypeDefinition.Kind == TypeKind.Interface) + .ToArray(); + + IEnumerable otherMembers = DeclaringTypeDefinition.Members; + if (SymbolKind == SymbolKind.Accessor) + otherMembers = DeclaringTypeDefinition.GetAccessors(options: GetMemberOptions.IgnoreInheritedMembers); + result = result.Where(item => !otherMembers.Any(m => m.IsExplicitInterfaceImplementation && m.ImplementedInterfaceMembers.Contains(item))).ToArray(); + + return result; + } + } + + public override DocumentationComment Documentation { + get { + IUnresolvedDocumentationProvider docProvider = unresolved.UnresolvedFile as IUnresolvedDocumentationProvider; + if (docProvider != null) { + var doc = docProvider.GetDocumentation(unresolved, this); + if (doc != null) + return doc; + } + return base.Documentation; + } + } + + public bool IsExplicitInterfaceImplementation { + get { return unresolved.IsExplicitInterfaceImplementation; } + } + + public bool IsVirtual { + get { return unresolved.IsVirtual; } + } + + public bool IsOverride { + get { return unresolved.IsOverride; } + } + + public bool IsOverridable { + get { return unresolved.IsOverridable; } + } + + public TypeParameterSubstitution Substitution { + get { return TypeParameterSubstitution.Identity; } + } + + public abstract IMember Specialize(TypeParameterSubstitution substitution); + + IMemberReference IMember.ToReference() + { + return (IMemberReference)ToReference(); + } + + public override ISymbolReference ToReference() + { + var declType = this.DeclaringType; + var declTypeRef = declType != null ? declType.ToTypeReference() : SpecialType.UnknownType; + if (IsExplicitInterfaceImplementation && ImplementedInterfaceMembers.Count == 1) { + return new ExplicitInterfaceImplementationMemberReference(declTypeRef, ImplementedInterfaceMembers[0].ToReference()); + } else { + return new DefaultMemberReference(this.SymbolKind, declTypeRef, this.Name); + } + } + + public virtual IMemberReference ToMemberReference() + { + return (IMemberReference)ToReference(); + } + + internal IMethod GetAccessor(ref IMethod accessorField, IUnresolvedMethod unresolvedAccessor) + { + if (unresolvedAccessor == null) + return null; + IMethod result = LazyInit.VolatileRead(ref accessorField); + if (result != null) { + return result; + } else { + return LazyInit.GetOrSet(ref accessorField, CreateResolvedAccessor(unresolvedAccessor)); + } + } + + protected virtual IMethod CreateResolvedAccessor(IUnresolvedMethod unresolvedAccessor) + { + return (IMethod)unresolvedAccessor.CreateResolved(context); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs new file mode 100644 index 000000000..857db81c0 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs @@ -0,0 +1,412 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Globalization; + +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + public abstract class AbstractTypeParameter : ITypeParameter, ICompilationProvider + { + readonly ICompilation compilation; + readonly SymbolKind ownerType; + readonly IEntity owner; + readonly int index; + readonly string name; + readonly IList attributes; + readonly DomRegion region; + readonly VarianceModifier variance; + + protected AbstractTypeParameter(IEntity owner, int index, string name, VarianceModifier variance, IList attributes, DomRegion region) + { + if (owner == null) + throw new ArgumentNullException("owner"); + this.owner = owner; + this.compilation = owner.Compilation; + this.ownerType = owner.SymbolKind; + this.index = index; + this.name = name ?? ((this.OwnerType == SymbolKind.Method ? "!!" : "!") + index.ToString(CultureInfo.InvariantCulture)); + this.attributes = attributes ?? EmptyList.Instance; + this.region = region; + this.variance = variance; + } + + protected AbstractTypeParameter(ICompilation compilation, SymbolKind ownerType, int index, string name, VarianceModifier variance, IList attributes, DomRegion region) + { + if (compilation == null) + throw new ArgumentNullException("compilation"); + this.compilation = compilation; + this.ownerType = ownerType; + this.index = index; + this.name = name ?? ((this.OwnerType == SymbolKind.Method ? "!!" : "!") + index.ToString(CultureInfo.InvariantCulture)); + this.attributes = attributes ?? EmptyList.Instance; + this.region = region; + this.variance = variance; + } + + SymbolKind ISymbol.SymbolKind { + get { return SymbolKind.TypeParameter; } + } + + public SymbolKind OwnerType { + get { return ownerType; } + } + + public IEntity Owner { + get { return owner; } + } + + public int Index { + get { return index; } + } + + public IList Attributes { + get { return attributes; } + } + + public VarianceModifier Variance { + get { return variance; } + } + + public DomRegion Region { + get { return region; } + } + + public ICompilation Compilation { + get { return compilation; } + } + + volatile IType effectiveBaseClass; + + public IType EffectiveBaseClass { + get { + if (effectiveBaseClass == null) { + // protect against cyclic type parameters + using (var busyLock = BusyManager.Enter(this)) { + if (!busyLock.Success) + return SpecialType.UnknownType; // don't cache this error + effectiveBaseClass = CalculateEffectiveBaseClass(); + } + } + return effectiveBaseClass; + } + } + + IType CalculateEffectiveBaseClass() + { + if (HasValueTypeConstraint) + return this.Compilation.FindType(KnownTypeCode.ValueType); + + List classTypeConstraints = new List(); + foreach (IType constraint in this.DirectBaseTypes) { + if (constraint.Kind == TypeKind.Class) { + classTypeConstraints.Add(constraint); + } else if (constraint.Kind == TypeKind.TypeParameter) { + IType baseClass = ((ITypeParameter)constraint).EffectiveBaseClass; + if (baseClass.Kind == TypeKind.Class) + classTypeConstraints.Add(baseClass); + } + } + if (classTypeConstraints.Count == 0) + return this.Compilation.FindType(KnownTypeCode.Object); + // Find the derived-most type in the resulting set: + IType result = classTypeConstraints[0]; + for (int i = 1; i < classTypeConstraints.Count; i++) { + if (classTypeConstraints[i].GetDefinition().IsDerivedFrom(result.GetDefinition())) + result = classTypeConstraints[i]; + } + return result; + } + + ICollection effectiveInterfaceSet; + + public ICollection EffectiveInterfaceSet { + get { + var result = LazyInit.VolatileRead(ref effectiveInterfaceSet); + if (result != null) { + return result; + } else { + // protect against cyclic type parameters + using (var busyLock = BusyManager.Enter(this)) { + if (!busyLock.Success) + return EmptyList.Instance; // don't cache this error + return LazyInit.GetOrSet(ref effectiveInterfaceSet, CalculateEffectiveInterfaceSet()); + } + } + } + } + + ICollection CalculateEffectiveInterfaceSet() + { + HashSet result = new HashSet(); + foreach (IType constraint in this.DirectBaseTypes) { + if (constraint.Kind == TypeKind.Interface) { + result.Add(constraint); + } else if (constraint.Kind == TypeKind.TypeParameter) { + result.UnionWith(((ITypeParameter)constraint).EffectiveInterfaceSet); + } + } + return result; + } + + public abstract bool HasDefaultConstructorConstraint { get; } + public abstract bool HasReferenceTypeConstraint { get; } + public abstract bool HasValueTypeConstraint { get; } + + public TypeKind Kind { + get { return TypeKind.TypeParameter; } + } + + public bool? IsReferenceType { + get { + if (this.HasValueTypeConstraint) + return false; + if (this.HasReferenceTypeConstraint) + return true; + + // A type parameter is known to be a reference type if it has the reference type constraint + // or its effective base class is not object or System.ValueType. + IType effectiveBaseClass = this.EffectiveBaseClass; + if (effectiveBaseClass.Kind == TypeKind.Class || effectiveBaseClass.Kind == TypeKind.Delegate) { + ITypeDefinition effectiveBaseClassDef = effectiveBaseClass.GetDefinition(); + if (effectiveBaseClassDef != null) { + switch (effectiveBaseClassDef.KnownTypeCode) { + case KnownTypeCode.Object: + case KnownTypeCode.ValueType: + case KnownTypeCode.Enum: + return null; + } + } + return true; + } else if (effectiveBaseClass.Kind == TypeKind.Struct || effectiveBaseClass.Kind == TypeKind.Enum) { + return false; + } + return null; + } + } + + IType IType.DeclaringType { + get { return null; } + } + + int IType.TypeParameterCount { + get { return 0; } + } + + bool IType.IsParameterized { + get { return false; } + } + + readonly static IList emptyTypeArguments = new IType[0]; + IList IType.TypeArguments { + get { return emptyTypeArguments; } + } + + public abstract IEnumerable DirectBaseTypes { get; } + + public string Name { + get { return name; } + } + + string INamedElement.Namespace { + get { return string.Empty; } + } + + string INamedElement.FullName { + get { return name; } + } + + public string ReflectionName { + get { + return (this.OwnerType == SymbolKind.Method ? "``" : "`") + index.ToString(CultureInfo.InvariantCulture); + } + } + + ITypeDefinition IType.GetDefinition() + { + return null; + } + + public IType AcceptVisitor(TypeVisitor visitor) + { + return visitor.VisitTypeParameter(this); + } + + public IType VisitChildren(TypeVisitor visitor) + { + return this; + } + + public ITypeReference ToTypeReference() + { + return TypeParameterReference.Create(this.OwnerType, this.Index); + } + + IEnumerable IType.GetNestedTypes(Predicate filter, GetMemberOptions options) + { + return EmptyList.Instance; + } + + IEnumerable IType.GetNestedTypes(IList typeArguments, Predicate filter, GetMemberOptions options) + { + return EmptyList.Instance; + } + + public IEnumerable GetConstructors(Predicate filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + if (this.HasDefaultConstructorConstraint || this.HasValueTypeConstraint) { + if (filter == null || filter(DefaultUnresolvedMethod.DummyConstructor)) { + return new [] { DefaultResolvedMethod.GetDummyConstructor(compilation, this) }; + } + } + return EmptyList.Instance; + } else { + return GetMembersHelper.GetConstructors(this, filter, options); + } + } + + public IEnumerable GetMethods(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) + return EmptyList.Instance; + else + return GetMembersHelper.GetMethods(this, FilterNonStatic(filter), options); + } + + public IEnumerable GetMethods(IList typeArguments, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) + return EmptyList.Instance; + else + return GetMembersHelper.GetMethods(this, typeArguments, FilterNonStatic(filter), options); + } + + public IEnumerable GetProperties(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) + return EmptyList.Instance; + else + return GetMembersHelper.GetProperties(this, FilterNonStatic(filter), options); + } + + public IEnumerable GetFields(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) + return EmptyList.Instance; + else + return GetMembersHelper.GetFields(this, FilterNonStatic(filter), options); + } + + public IEnumerable GetEvents(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) + return EmptyList.Instance; + else + return GetMembersHelper.GetEvents(this, FilterNonStatic(filter), options); + } + + public IEnumerable GetMembers(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) + return EmptyList.Instance; + else + return GetMembersHelper.GetMembers(this, FilterNonStatic(filter), options); + } + + public IEnumerable GetAccessors(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) + return EmptyList.Instance; + else + return GetMembersHelper.GetAccessors(this, FilterNonStatic(filter), options); + } + + public TypeParameterSubstitution GetSubstitution() + { + return TypeParameterSubstitution.Identity; + } + + public TypeParameterSubstitution GetSubstitution(IList methodTypeArguments) + { + return TypeParameterSubstitution.Identity; + } + + static Predicate FilterNonStatic(Predicate filter) where T : class, IUnresolvedMember + { + if (filter == null) + return member => !member.IsStatic; + else + return member => !member.IsStatic && filter(member); + } + + public sealed override bool Equals(object obj) + { + return Equals(obj as IType); + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public virtual bool Equals(IType other) + { + return this == other; // use reference equality for type parameters + } + + public virtual ISymbolReference ToReference() + { + if (owner == null) + return TypeParameterReference.Create(ownerType, index); + return new OwnedTypeParameterReference(owner.ToReference(), index); + } + + public override string ToString() + { + return this.ReflectionName + " (owner=" + owner + ")"; + } + } + + public sealed class OwnedTypeParameterReference : ISymbolReference + { + ISymbolReference owner; + int index; + + public OwnedTypeParameterReference(ISymbolReference owner, int index) + { + if (owner == null) + throw new ArgumentNullException("owner"); + this.owner = owner; + this.index = index; + } + + public ISymbol Resolve(ITypeResolveContext context) + { + var entity = owner.Resolve(context) as IEntity; + if (entity is ITypeDefinition) + return ((ITypeDefinition)entity).TypeParameters[index]; + if (entity is IMethod) + return ((IMethod)entity).TypeParameters[index]; + return null; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractType.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractType.cs new file mode 100644 index 000000000..c86ff87fd --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractType.cs @@ -0,0 +1,180 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Diagnostics.Contracts; +using System.Linq; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Default implementation for IType interface. + /// + [Serializable] + public abstract class AbstractType : IType + { + public virtual string FullName { + get { + string ns = this.Namespace; + string name = this.Name; + if (string.IsNullOrEmpty(ns)) { + return name; + } else { + return ns + "." + name; + } + } + } + + public abstract string Name { get; } + + public virtual string Namespace { + get { return string.Empty; } + } + + public virtual string ReflectionName { + get { return this.FullName; } + } + + public abstract bool? IsReferenceType { get; } + + public abstract TypeKind Kind { get; } + + public virtual int TypeParameterCount { + get { return 0; } + } + + readonly static IList emptyTypeArguments = new IType[0]; + public virtual IList TypeArguments { + get { return emptyTypeArguments; } + } + + public virtual IType DeclaringType { + get { return null; } + } + + public virtual bool IsParameterized { + get { return false; } + } + + public virtual ITypeDefinition GetDefinition() + { + return null; + } + + public virtual IEnumerable DirectBaseTypes { + get { return EmptyList.Instance; } + } + + public abstract ITypeReference ToTypeReference(); + + public virtual IEnumerable GetNestedTypes(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + return EmptyList.Instance; + } + + public virtual IEnumerable GetNestedTypes(IList typeArguments, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + return EmptyList.Instance; + } + + public virtual IEnumerable GetMethods(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + return EmptyList.Instance; + } + + public virtual IEnumerable GetMethods(IList typeArguments, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + return EmptyList.Instance; + } + + public virtual IEnumerable GetConstructors(Predicate filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers) + { + return EmptyList.Instance; + } + + public virtual IEnumerable GetProperties(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + return EmptyList.Instance; + } + + public virtual IEnumerable GetFields(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + return EmptyList.Instance; + } + + public virtual IEnumerable GetEvents(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + return EmptyList.Instance; + } + + public virtual IEnumerable GetMembers(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + IEnumerable members = GetMethods(filter, options); + return members + .Concat(GetProperties(filter, options)) + .Concat(GetFields(filter, options)) + .Concat(GetEvents(filter, options)); + } + + public virtual IEnumerable GetAccessors(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + return EmptyList.Instance; + } + + public TypeParameterSubstitution GetSubstitution() + { + return TypeParameterSubstitution.Identity; + } + + public TypeParameterSubstitution GetSubstitution(IList methodTypeArguments) + { + return TypeParameterSubstitution.Identity; + } + + public override sealed bool Equals(object obj) + { + return Equals(obj as IType); + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public virtual bool Equals(IType other) + { + return this == other; // use reference equality by default + } + + public override string ToString() + { + return this.ReflectionName; + } + + public virtual IType AcceptVisitor(TypeVisitor visitor) + { + return visitor.VisitOtherType(this); + } + + public virtual IType VisitChildren(TypeVisitor visitor) + { + return this; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractUnresolvedEntity.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractUnresolvedEntity.cs new file mode 100644 index 000000000..c92291312 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractUnresolvedEntity.cs @@ -0,0 +1,334 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Text; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Base class for implementations. + /// + [Serializable] + public abstract class AbstractUnresolvedEntity : IUnresolvedEntity, IFreezable + { + // possible optimizations to reduce the memory usage of AbstractUnresolvedEntity: + // - store regions in more compact form (e.g. assume both file names are identical; use ushort for columns) + + IUnresolvedTypeDefinition declaringTypeDefinition; + + string name = string.Empty; + IList attributes; + internal RareFields rareFields; + + // 1 byte per enum + 2 bytes for flags + SymbolKind symbolKind; + Accessibility accessibility; + internal BitVector16 flags; + + // flags for AbstractUnresolvedEntity: + internal const ushort FlagFrozen = 0x0001; + internal const ushort FlagSealed = 0x0002; + internal const ushort FlagAbstract = 0x0004; + internal const ushort FlagShadowing = 0x0008; + internal const ushort FlagSynthetic = 0x0010; + internal const ushort FlagStatic = 0x0020; + // flags for DefaultUnresolvedTypeDefinition/LazyCecilTypeDefinition + internal const ushort FlagAddDefaultConstructorIfRequired = 0x0040; + internal const ushort FlagHasExtensionMethods = 0x0080; + internal const ushort FlagHasNoExtensionMethods = 0x0100; + internal const ushort FlagPartialTypeDefinition = 0x0200; + // flags for AbstractUnresolvedMember: + internal const ushort FlagExplicitInterfaceImplementation = 0x0040; + internal const ushort FlagVirtual = 0x0080; + internal const ushort FlagOverride = 0x0100; + // flags for DefaultField: + internal const ushort FlagFieldIsReadOnly = 0x1000; + internal const ushort FlagFieldIsVolatile = 0x2000; + internal const ushort FlagFieldIsFixedSize = 0x4000; + // flags for DefaultMethod: + internal const ushort FlagExtensionMethod = 0x1000; + internal const ushort FlagPartialMethod = 0x2000; + internal const ushort FlagHasBody = 0x4000; + internal const ushort FlagAsyncMethod = 0x8000; + + public bool IsFrozen { + get { return flags[FlagFrozen]; } + } + + public void Freeze() + { + if (!flags[FlagFrozen]) { + FreezeInternal(); + flags[FlagFrozen] = true; + } + } + + protected virtual void FreezeInternal() + { + attributes = FreezableHelper.FreezeListAndElements(attributes); + if (rareFields != null) + rareFields.FreezeInternal(); + } + + /// + /// Uses the specified interning provider to intern + /// strings and lists in this entity. + /// This method does not test arbitrary objects to see if they implement ISupportsInterning; + /// instead we assume that those are interned immediately when they are created (before they are added to this entity). + /// + public virtual void ApplyInterningProvider(InterningProvider provider) + { + if (provider == null) + throw new ArgumentNullException("provider"); + ThrowIfFrozen(); + name = provider.Intern(name); + attributes = provider.InternList(attributes); + if (rareFields != null) + rareFields.ApplyInterningProvider(provider); + } + + /// + /// Creates a shallow clone of this entity. + /// Collections (e.g. a type's member list) will be cloned as well, but the elements + /// of said list will not be. + /// If this instance is frozen, the clone will be unfrozen. + /// + public virtual object Clone() + { + var copy = (AbstractUnresolvedEntity)MemberwiseClone(); + copy.flags[FlagFrozen] = false; + if (attributes != null) + copy.attributes = new List(attributes); + if (rareFields != null) + copy.rareFields = (RareFields)rareFields.Clone(); + return copy; + } + + [Serializable] + internal class RareFields + { + internal DomRegion region; + internal DomRegion bodyRegion; + internal IUnresolvedFile unresolvedFile; + + protected internal virtual void FreezeInternal() + { + } + + public virtual void ApplyInterningProvider(InterningProvider provider) + { + } + + public virtual object Clone() + { + return MemberwiseClone(); + } + } + + protected void ThrowIfFrozen() + { + FreezableHelper.ThrowIfFrozen(this); + } + + public SymbolKind SymbolKind { + get { return symbolKind; } + set { + ThrowIfFrozen(); + symbolKind = value; + } + } + + internal virtual RareFields WriteRareFields() + { + ThrowIfFrozen(); + if (rareFields == null) rareFields = new RareFields(); + return rareFields; + } + + public DomRegion Region { + get { return rareFields != null ? rareFields.region : DomRegion.Empty; } + set { + if (value != DomRegion.Empty || rareFields != null) + WriteRareFields().region = value; + } + } + + public DomRegion BodyRegion { + get { return rareFields != null ? rareFields.bodyRegion : DomRegion.Empty; } + set { + if (value != DomRegion.Empty || rareFields != null) + WriteRareFields().bodyRegion = value; + } + } + + public IUnresolvedFile UnresolvedFile { + get { return rareFields != null ? rareFields.unresolvedFile : null; } + set { + if (value != null || rareFields != null) + WriteRareFields().unresolvedFile = value; + } + } + + public IUnresolvedTypeDefinition DeclaringTypeDefinition { + get { return declaringTypeDefinition; } + set { + ThrowIfFrozen(); + declaringTypeDefinition = value; + } + } + + public IList Attributes { + get { + if (attributes == null) + attributes = new List(); + return attributes; + } + } + + public string Name { + get { return name; } + set { + if (value == null) + throw new ArgumentNullException("value"); + ThrowIfFrozen(); + name = value; + } + } + + public virtual string FullName { + get { + if (declaringTypeDefinition != null) + return declaringTypeDefinition.FullName + "." + name; + else if (!string.IsNullOrEmpty(this.Namespace)) + return this.Namespace + "." + name; + else + return name; + } + } + + public virtual string Namespace { + get { + if (declaringTypeDefinition != null) + return declaringTypeDefinition.Namespace; + else + return string.Empty; + } + set { + throw new NotSupportedException(); + } + } + + public virtual string ReflectionName { + get { + if (declaringTypeDefinition != null) + return declaringTypeDefinition.ReflectionName + "." + name; + else + return name; + } + } + + public Accessibility Accessibility { + get { return accessibility; } + set { + ThrowIfFrozen(); + accessibility = value; + } + } + + public bool IsStatic { + get { return flags[FlagStatic]; } + set { + ThrowIfFrozen(); + flags[FlagStatic] = value; + } + } + + public bool IsAbstract { + get { return flags[FlagAbstract]; } + set { + ThrowIfFrozen(); + flags[FlagAbstract] = value; + } + } + + public bool IsSealed { + get { return flags[FlagSealed]; } + set { + ThrowIfFrozen(); + flags[FlagSealed] = value; + } + } + + public bool IsShadowing { + get { return flags[FlagShadowing]; } + set { + ThrowIfFrozen(); + flags[FlagShadowing] = value; + } + } + + public bool IsSynthetic { + get { return flags[FlagSynthetic]; } + set { + ThrowIfFrozen(); + flags[FlagSynthetic] = value; + } + } + + bool IHasAccessibility.IsPrivate { + get { return accessibility == Accessibility.Private; } + } + + bool IHasAccessibility.IsPublic { + get { return accessibility == Accessibility.Public; } + } + + bool IHasAccessibility.IsProtected { + get { return accessibility == Accessibility.Protected; } + } + + bool IHasAccessibility.IsInternal { + get { return accessibility == Accessibility.Internal; } + } + + bool IHasAccessibility.IsProtectedOrInternal { + get { return accessibility == Accessibility.ProtectedOrInternal; } + } + + bool IHasAccessibility.IsProtectedAndInternal { + get { return accessibility == Accessibility.ProtectedAndInternal; } + } + + public override string ToString() + { + StringBuilder b = new StringBuilder("["); + b.Append(GetType().Name); + b.Append(' '); + if (this.DeclaringTypeDefinition != null) { + b.Append(this.DeclaringTypeDefinition.Name); + b.Append('.'); + } + b.Append(this.Name); + b.Append(']'); + return b.ToString(); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractUnresolvedMember.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractUnresolvedMember.cs new file mode 100644 index 000000000..d4d47c251 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractUnresolvedMember.cs @@ -0,0 +1,272 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Base class for implementations. + /// + [Serializable] + public abstract class AbstractUnresolvedMember : AbstractUnresolvedEntity, IUnresolvedMember + { + ITypeReference returnType = SpecialType.UnknownType; + IList interfaceImplementations; + + public override void ApplyInterningProvider(InterningProvider provider) + { + base.ApplyInterningProvider(provider); + interfaceImplementations = provider.InternList(interfaceImplementations); + } + + protected override void FreezeInternal() + { + base.FreezeInternal(); + interfaceImplementations = FreezableHelper.FreezeList(interfaceImplementations); + } + + public override object Clone() + { + var copy = (AbstractUnresolvedMember)base.Clone(); + if (interfaceImplementations != null) + copy.interfaceImplementations = new List(interfaceImplementations); + return copy; + } + + /* + [Serializable] + internal new class RareFields : AbstractUnresolvedEntity.RareFields + { + internal IList interfaceImplementations; + + public override void ApplyInterningProvider(IInterningProvider provider) + { + base.ApplyInterningProvider(provider); + interfaceImplementations = provider.InternList(interfaceImplementations); + } + + protected internal override void FreezeInternal() + { + interfaceImplementations = FreezableHelper.FreezeListAndElements(interfaceImplementations); + base.FreezeInternal(); + } + + override Clone(){} + } + + internal override AbstractUnresolvedEntity.RareFields WriteRareFields() + { + ThrowIfFrozen(); + if (rareFields == null) rareFields = new RareFields(); + return rareFields; + }*/ + + public ITypeReference ReturnType { + get { return returnType; } + set { + if (value == null) + throw new ArgumentNullException("value"); + ThrowIfFrozen(); + returnType = value; + } + } + + public bool IsExplicitInterfaceImplementation { + get { return flags[FlagExplicitInterfaceImplementation]; } + set { + ThrowIfFrozen(); + flags[FlagExplicitInterfaceImplementation] = value; + } + } + + public IList ExplicitInterfaceImplementations { + get { + /* + RareFields rareFields = (RareFields)this.rareFields; + if (rareFields == null || rareFields.interfaceImplementations == null) { + rareFields = (RareFields)WriteRareFields(); + return rareFields.interfaceImplementations = new List(); + } + return rareFields.interfaceImplementations; + */ + if (interfaceImplementations == null) + interfaceImplementations = new List(); + return interfaceImplementations; + } + } + + public bool IsVirtual { + get { return flags[FlagVirtual]; } + set { + ThrowIfFrozen(); + flags[FlagVirtual] = value; + } + } + + public bool IsOverride { + get { return flags[FlagOverride]; } + set { + ThrowIfFrozen(); + flags[FlagOverride] = value; + } + } + + public bool IsOverridable { + get { + // override or virtual or abstract but not sealed + return (flags.Data & (FlagOverride | FlagVirtual | FlagAbstract)) != 0 && !this.IsSealed; + } + } + + ITypeReference IMemberReference.DeclaringTypeReference { + get { return this.DeclaringTypeDefinition; } + } + + #region Resolve + public abstract IMember CreateResolved(ITypeResolveContext context); + + public virtual IMember Resolve(ITypeResolveContext context) + { + ITypeReference interfaceTypeReference = null; + if (this.IsExplicitInterfaceImplementation && this.ExplicitInterfaceImplementations.Count == 1) + interfaceTypeReference = this.ExplicitInterfaceImplementations[0].DeclaringTypeReference; + return Resolve(ExtendContextForType(context, this.DeclaringTypeDefinition), this.SymbolKind, this.Name, interfaceTypeReference); + } + + ISymbol ISymbolReference.Resolve(ITypeResolveContext context) + { + return ((IUnresolvedMember)this).Resolve(context); + } + + protected static ITypeResolveContext ExtendContextForType(ITypeResolveContext assemblyContext, IUnresolvedTypeDefinition typeDef) + { + if (typeDef == null) + return assemblyContext; + ITypeResolveContext parentContext; + if (typeDef.DeclaringTypeDefinition != null) + parentContext = ExtendContextForType(assemblyContext, typeDef.DeclaringTypeDefinition); + else + parentContext = assemblyContext; + ITypeDefinition resolvedTypeDef = typeDef.Resolve(assemblyContext).GetDefinition(); + return typeDef.CreateResolveContext(parentContext).WithCurrentTypeDefinition(resolvedTypeDef); + } + + public static IMember Resolve(ITypeResolveContext context, + SymbolKind symbolKind, + string name, + ITypeReference explicitInterfaceTypeReference = null, + IList typeParameterNames = null, + IList parameterTypeReferences = null) + { + if (context.CurrentTypeDefinition == null) + return null; + if (parameterTypeReferences == null) + parameterTypeReferences = EmptyList.Instance; + if (typeParameterNames == null || typeParameterNames.Count == 0) { + // non-generic member + // In this case, we can simply resolve the parameter types in the given context + var parameterTypes = parameterTypeReferences.Resolve(context); + if (explicitInterfaceTypeReference == null) { + foreach (IMember member in context.CurrentTypeDefinition.Members) { + if (member.IsExplicitInterfaceImplementation) + continue; + if (IsNonGenericMatch(member, symbolKind, name, parameterTypes)) + return member; + } + } else { + IType explicitInterfaceType = explicitInterfaceTypeReference.Resolve(context); + foreach (IMember member in context.CurrentTypeDefinition.Members) { + if (!member.IsExplicitInterfaceImplementation) + continue; + if (member.ImplementedInterfaceMembers.Count != 1) + continue; + if (IsNonGenericMatch(member, symbolKind, name, parameterTypes)) { + if (explicitInterfaceType.Equals(member.ImplementedInterfaceMembers[0].DeclaringType)) + return member; + } + } + } + } else { + // generic member + // In this case, we must specify the correct context for resolving the parameter types + foreach (IMethod method in context.CurrentTypeDefinition.Methods) { + if (method.SymbolKind != symbolKind) + continue; + if (method.Name != name) + continue; + if (method.Parameters.Count != parameterTypeReferences.Count) + continue; + // Compare type parameter count and names: + if (!typeParameterNames.SequenceEqual(method.TypeParameters.Select(tp => tp.Name))) + continue; + // Once we know the type parameter names are fitting, we can resolve the + // type references in the context of the method: + var contextForMethod = context.WithCurrentMember(method); + var parameterTypes = parameterTypeReferences.Resolve(contextForMethod); + if (!IsParameterTypeMatch(method, parameterTypes)) + continue; + if (explicitInterfaceTypeReference == null) { + if (!method.IsExplicitInterfaceImplementation) + return method; + } else if (method.IsExplicitInterfaceImplementation && method.ImplementedInterfaceMembers.Count == 1) { + IType explicitInterfaceType = explicitInterfaceTypeReference.Resolve(contextForMethod); + if (explicitInterfaceType.Equals(method.ImplementedInterfaceMembers[0].DeclaringType)) + return method; + } + } + } + return null; + } + + static bool IsNonGenericMatch(IMember member, SymbolKind symbolKind, string name, IList parameterTypes) + { + if (member.SymbolKind != symbolKind) + return false; + if (member.Name != name) + return false; + IMethod method = member as IMethod; + if (method != null && method.TypeParameters.Count > 0) + return false; + return IsParameterTypeMatch(member, parameterTypes); + } + + static bool IsParameterTypeMatch(IMember member, IList parameterTypes) + { + IParameterizedMember parameterizedMember = member as IParameterizedMember; + if (parameterizedMember == null) { + return parameterTypes.Count == 0; + } else if (parameterTypes.Count == parameterizedMember.Parameters.Count) { + for (int i = 0; i < parameterTypes.Count; i++) { + IType type1 = parameterTypes[i]; + IType type2 = parameterizedMember.Parameters[i].Type; + if (!type1.Equals(type2)) { + return false; + } + } + return true; + } else { + return false; + } + } + #endregion + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/AccessorOwnerMemberReference.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/AccessorOwnerMemberReference.cs new file mode 100644 index 000000000..5db066b6e --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/AccessorOwnerMemberReference.cs @@ -0,0 +1,56 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Given a reference to an accessor, returns the accessor's owner. + /// + [Serializable] + sealed class AccessorOwnerMemberReference : IMemberReference + { + readonly IMemberReference accessorReference; + + public AccessorOwnerMemberReference(IMemberReference accessorReference) + { + if (accessorReference == null) + throw new ArgumentNullException("accessorReference"); + this.accessorReference = accessorReference; + } + + public ITypeReference DeclaringTypeReference { + get { return accessorReference.DeclaringTypeReference; } + } + + public IMember Resolve(ITypeResolveContext context) + { + IMethod method = accessorReference.Resolve(context) as IMethod; + if (method != null) + return method.AccessorOwner; + else + return null; + } + + ISymbol ISymbolReference.Resolve(ITypeResolveContext context) + { + return ((IMemberReference)this).Resolve(context); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/BaseTypeCollector.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/BaseTypeCollector.cs new file mode 100644 index 000000000..04df5df6f --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/BaseTypeCollector.cs @@ -0,0 +1,75 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Helper class for the GetAllBaseTypes() implementation. + /// + sealed class BaseTypeCollector : List + { + readonly Stack activeTypes = new Stack(); + + /// + /// If this option is enabled, the list will not contain interfaces when retrieving the base types + /// of a class. + /// + internal bool SkipImplementedInterfaces; + + public void CollectBaseTypes(IType type) + { + IType def = type.GetDefinition() ?? type; + + // Maintain a stack of currently active type definitions, and avoid having one definition + // multiple times on that stack. + // This is necessary to ensure the output is finite in the presence of cyclic inheritance: + // class C : C> {} would not be caught by the 'no duplicate output' check, yet would + // produce infinite output. + if (activeTypes.Contains(def)) + return; + activeTypes.Push(def); + // Note that we also need to push non-type definitions, e.g. for protecting against + // cyclic inheritance in type parameters (where T : S where S : T). + // The output check doesn't help there because we call Add(type) only at the end. + // We can't simply call this.Add(type); at the start because that would return in an incorrect order. + + // Avoid outputting a type more than once - necessary for "diamond" multiple inheritance + // (e.g. C implements I1 and I2, and both interfaces derive from Object) + if (!this.Contains(type)) { + foreach (IType baseType in type.DirectBaseTypes) { + if (SkipImplementedInterfaces && def != null && def.Kind != TypeKind.Interface && def.Kind != TypeKind.TypeParameter) { + if (baseType.Kind == TypeKind.Interface) { + // skip the interface + continue; + } + } + CollectBaseTypes(baseType); + } + // Add(type) at the end - we want a type to be output only after all its base types were added. + this.Add(type); + // Note that this is not the same as putting the this.Add() call in front and then reversing the list. + // For the diamond inheritance, Add() at the start produces "C, I1, Object, I2", + // while Add() at the end produces "Object, I1, I2, C". + } + activeTypes.Pop(); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/BlobReader.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/BlobReader.cs new file mode 100644 index 000000000..3e6a420cd --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/BlobReader.cs @@ -0,0 +1,387 @@ +// +// BlobReader.cs +// +// Author: +// Daniel Grunwald +// +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Semantics; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + sealed class BlobReader + { + internal static int GetBlobHashCode(byte[] blob) + { + unchecked { + int hash = 0; + foreach (byte b in blob) { + hash *= 257; + hash += b; + } + return hash; + } + } + + internal static bool BlobEquals(byte[] a, byte[] b) + { + if (a.Length != b.Length) + return false; + for (int i = 0; i < a.Length; i++) { + if (a[i] != b[i]) + return false; + } + return true; + } + + byte[] buffer; + int position; + readonly IAssembly currentResolvedAssembly; + + public BlobReader(byte[] buffer, IAssembly currentResolvedAssembly) + { + if (buffer == null) + throw new ArgumentNullException("buffer"); + this.buffer = buffer; + this.currentResolvedAssembly = currentResolvedAssembly; + } + + public byte ReadByte() + { + return buffer[position++]; + } + + public sbyte ReadSByte() + { + unchecked { + return(sbyte) ReadByte(); + } + } + + public byte[] ReadBytes(int length) + { + var bytes = new byte[length]; + Buffer.BlockCopy(buffer, position, bytes, 0, length); + position += length; + return bytes; + } + + public ushort ReadUInt16() + { + unchecked { + ushort value =(ushort)(buffer[position] + |(buffer[position + 1] << 8)); + position += 2; + return value; + } + } + + public short ReadInt16() + { + unchecked { + return(short) ReadUInt16(); + } + } + + public uint ReadUInt32() + { + unchecked { + uint value =(uint)(buffer[position] + |(buffer[position + 1] << 8) + |(buffer[position + 2] << 16) + |(buffer[position + 3] << 24)); + position += 4; + return value; + } + } + + public int ReadInt32() + { + unchecked { + return(int) ReadUInt32(); + } + } + + public ulong ReadUInt64() + { + unchecked { + uint low = ReadUInt32(); + uint high = ReadUInt32(); + + return(((ulong) high) << 32) | low; + } + } + + public long ReadInt64() + { + unchecked { + return(long) ReadUInt64(); + } + } + + public uint ReadCompressedUInt32() + { + unchecked { + byte first = ReadByte(); + if((first & 0x80) == 0) + return first; + + if((first & 0x40) == 0) + return((uint)(first & ~0x80) << 8) + | ReadByte(); + + return((uint)(first & ~0xc0) << 24) + |(uint) ReadByte() << 16 + |(uint) ReadByte() << 8 + | ReadByte(); + } + } + + public float ReadSingle() + { + unchecked { + if(!BitConverter.IsLittleEndian) { + var bytes = ReadBytes(4); + Array.Reverse(bytes); + return BitConverter.ToSingle(bytes, 0); + } + + float value = BitConverter.ToSingle(buffer, position); + position += 4; + return value; + } + } + + public double ReadDouble() + { + unchecked { + if(!BitConverter.IsLittleEndian) { + var bytes = ReadBytes(8); + Array.Reverse(bytes); + return BitConverter.ToDouble(bytes, 0); + } + + double value = BitConverter.ToDouble(buffer, position); + position += 8; + return value; + } + } + + public ResolveResult ReadFixedArg(IType argType) + { + if (argType.Kind == TypeKind.Array) { + if (((ArrayType)argType).Dimensions != 1) { + // Only single-dimensional arrays are supported + return ErrorResolveResult.UnknownError; + } + IType elementType = ((ArrayType)argType).ElementType; + uint numElem = ReadUInt32(); + if (numElem == 0xffffffff) { + // null reference + return new ConstantResolveResult(argType, null); + } else { + ResolveResult[] elements = new ResolveResult[numElem]; + for (int i = 0; i < elements.Length; i++) { + elements[i] = ReadElem(elementType); + // Stop decoding when encountering an error: + if (elements[i].IsError) + return ErrorResolveResult.UnknownError; + } + IType int32 = currentResolvedAssembly.Compilation.FindType(KnownTypeCode.Int32); + ResolveResult[] sizeArgs = { new ConstantResolveResult(int32, elements.Length) }; + return new ArrayCreateResolveResult(argType, sizeArgs, elements); + } + } else { + return ReadElem(argType); + } + } + + public ResolveResult ReadElem(IType elementType) + { + ITypeDefinition underlyingType; + if (elementType.Kind == TypeKind.Enum) { + underlyingType = elementType.GetDefinition().EnumUnderlyingType.GetDefinition(); + } else { + underlyingType = elementType.GetDefinition(); + } + if (underlyingType == null) + return ErrorResolveResult.UnknownError; + KnownTypeCode typeCode = underlyingType.KnownTypeCode; + if (typeCode == KnownTypeCode.Object) { + // boxed value type + IType boxedTyped = ReadCustomAttributeFieldOrPropType(); + ResolveResult elem = ReadFixedArg(boxedTyped); + if (elem.IsCompileTimeConstant && elem.ConstantValue == null) + return new ConstantResolveResult(elementType, null); + else + return new ConversionResolveResult(elementType, elem, Conversion.BoxingConversion); + } else if (typeCode == KnownTypeCode.Type) { + return new TypeOfResolveResult(underlyingType, ReadType()); + } else { + return new ConstantResolveResult(elementType, ReadElemValue(typeCode)); + } + } + + object ReadElemValue(KnownTypeCode typeCode) + { + switch (typeCode) { + case KnownTypeCode.Boolean: + return ReadByte() != 0; + case KnownTypeCode.Char: + return (char)ReadUInt16(); + case KnownTypeCode.SByte: + return ReadSByte(); + case KnownTypeCode.Byte: + return ReadByte(); + case KnownTypeCode.Int16: + return ReadInt16(); + case KnownTypeCode.UInt16: + return ReadUInt16(); + case KnownTypeCode.Int32: + return ReadInt32(); + case KnownTypeCode.UInt32: + return ReadUInt32(); + case KnownTypeCode.Int64: + return ReadInt64(); + case KnownTypeCode.UInt64: + return ReadUInt64(); + case KnownTypeCode.Single: + return ReadSingle(); + case KnownTypeCode.Double: + return ReadDouble(); + case KnownTypeCode.String: + return ReadSerString(); + default: + throw new NotSupportedException(); + } + } + + public string ReadSerString () + { + if (buffer [position] == 0xff) { + position++; + return null; + } + + int length = (int) ReadCompressedUInt32(); + if (length == 0) + return string.Empty; + + string @string = System.Text.Encoding.UTF8.GetString( + buffer, position, + buffer [position + length - 1] == 0 ? length - 1 : length); + + position += length; + return @string; + } + + public KeyValuePair ReadNamedArg(IType attributeType) + { + SymbolKind memberType; + var b = ReadByte(); + switch (b) { + case 0x53: + memberType = SymbolKind.Field; + break; + case 0x54: + memberType = SymbolKind.Property; + break; + default: + throw new NotSupportedException(string.Format("Custom member type 0x{0:x} is not supported.", b)); + } + IType type = ReadCustomAttributeFieldOrPropType(); + string name = ReadSerString(); + ResolveResult val = ReadFixedArg(type); + IMember member = null; + // Use last matching member, as GetMembers() returns members from base types first. + foreach (IMember m in attributeType.GetMembers(m => m.SymbolKind == memberType && m.Name == name)) { + if (m.ReturnType.Equals(type)) + member = m; + } + return new KeyValuePair(member, val); + } + + IType ReadCustomAttributeFieldOrPropType() + { + ICompilation compilation = currentResolvedAssembly.Compilation; + var b = ReadByte(); + switch (b) { + case 0x02: + return compilation.FindType(KnownTypeCode.Boolean); + case 0x03: + return compilation.FindType(KnownTypeCode.Char); + case 0x04: + return compilation.FindType(KnownTypeCode.SByte); + case 0x05: + return compilation.FindType(KnownTypeCode.Byte); + case 0x06: + return compilation.FindType(KnownTypeCode.Int16); + case 0x07: + return compilation.FindType(KnownTypeCode.UInt16); + case 0x08: + return compilation.FindType(KnownTypeCode.Int32); + case 0x09: + return compilation.FindType(KnownTypeCode.UInt32); + case 0x0a: + return compilation.FindType(KnownTypeCode.Int64); + case 0x0b: + return compilation.FindType(KnownTypeCode.UInt64); + case 0x0c: + return compilation.FindType(KnownTypeCode.Single); + case 0x0d: + return compilation.FindType(KnownTypeCode.Double); + case 0x0e: + return compilation.FindType(KnownTypeCode.String); + case 0x1d: + return new ArrayType(compilation, ReadCustomAttributeFieldOrPropType()); + case 0x50: + return compilation.FindType(KnownTypeCode.Type); + case 0x51: // boxed value type + return compilation.FindType(KnownTypeCode.Object); + case 0x55: // enum + return ReadType(); + default: + throw new NotSupportedException(string.Format("Custom attribute type 0x{0:x} is not supported.", b)); + } + } + + IType ReadType() + { + string typeName = ReadSerString(); + ITypeReference typeReference = ReflectionHelper.ParseReflectionName(typeName); + IType typeInCurrentAssembly = typeReference.Resolve(new SimpleTypeResolveContext(currentResolvedAssembly)); + if (typeInCurrentAssembly.Kind != TypeKind.Unknown) + return typeInCurrentAssembly; + + // look for the type in mscorlib + ITypeDefinition systemObject = currentResolvedAssembly.Compilation.FindType(KnownTypeCode.Object).GetDefinition(); + if (systemObject != null) { + return typeReference.Resolve(new SimpleTypeResolveContext(systemObject.ParentAssembly)); + } else { + // couldn't find corlib - return the unknown IType for the current assembly + return typeInCurrentAssembly; + } + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultAssemblyReference.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultAssemblyReference.cs new file mode 100644 index 000000000..9f5f7e1ec --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultAssemblyReference.cs @@ -0,0 +1,87 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// References an existing assembly by name. + /// + [Serializable] + public sealed class DefaultAssemblyReference : IAssemblyReference, ISupportsInterning + { + public static readonly IAssemblyReference CurrentAssembly = new CurrentAssemblyReference(); + + [Obsolete("The corlib is not always called 'mscorlib' (as returned by this property), but might be 'System.Runtime'.")] + public static readonly IAssemblyReference Corlib = new DefaultAssemblyReference("mscorlib"); + + readonly string shortName; + + public DefaultAssemblyReference(string assemblyName) + { + int pos = assemblyName != null ? assemblyName.IndexOf(',') : -1; + if (pos >= 0) + shortName = assemblyName.Substring(0, pos); + else + shortName = assemblyName; + } + + public IAssembly Resolve(ITypeResolveContext context) + { + IAssembly current = context.CurrentAssembly; + if (current != null && string.Equals(shortName, current.AssemblyName, StringComparison.OrdinalIgnoreCase)) + return current; + foreach (IAssembly asm in context.Compilation.Assemblies) { + if (string.Equals(shortName, asm.AssemblyName, StringComparison.OrdinalIgnoreCase)) + return asm; + } + return null; + } + + public override string ToString() + { + return shortName; + } + + int ISupportsInterning.GetHashCodeForInterning() + { + unchecked { + return shortName.GetHashCode(); + } + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + DefaultAssemblyReference o = other as DefaultAssemblyReference; + return o != null && shortName == o.shortName; + } + + [Serializable] + sealed class CurrentAssemblyReference : IAssemblyReference + { + public IAssembly Resolve(ITypeResolveContext context) + { + IAssembly asm = context.CurrentAssembly; + if (asm == null) + throw new ArgumentException("A reference to the current assembly cannot be resolved in the compilation's global type resolve context."); + return asm; + } + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultAttribute.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultAttribute.cs new file mode 100644 index 000000000..53ddec9ad --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultAttribute.cs @@ -0,0 +1,97 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; +using ICSharpCode.NRefactory.Semantics; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// IAttribute implementation for already-resolved attributes. + /// + public class DefaultAttribute : IAttribute + { + readonly IType attributeType; + readonly IList positionalArguments; + readonly IList> namedArguments; + readonly DomRegion region; + volatile IMethod constructor; + + public DefaultAttribute(IType attributeType, IList positionalArguments = null, + IList> namedArguments = null, + DomRegion region = default(DomRegion)) + { + if (attributeType == null) + throw new ArgumentNullException("attributeType"); + this.attributeType = attributeType; + this.positionalArguments = positionalArguments ?? EmptyList.Instance; + this.namedArguments = namedArguments ?? EmptyList>.Instance; + this.region = region; + } + + public DefaultAttribute(IMethod constructor, IList positionalArguments = null, + IList> namedArguments = null, + DomRegion region = default(DomRegion)) + { + if (constructor == null) + throw new ArgumentNullException("constructor"); + this.constructor = constructor; + this.attributeType = constructor.DeclaringType ?? SpecialType.UnknownType; + this.positionalArguments = positionalArguments ?? EmptyList.Instance; + this.namedArguments = namedArguments ?? EmptyList>.Instance; + this.region = region; + if (this.positionalArguments.Count != constructor.Parameters.Count) { + throw new ArgumentException("Positional argument count must match the constructor's parameter count"); + } + } + + public IType AttributeType { + get { return attributeType; } + } + + public DomRegion Region { + get { return region; } + } + + public IMethod Constructor { + get { + IMethod ctor = this.constructor; + if (ctor == null) { + foreach (IMethod candidate in this.AttributeType.GetConstructors(m => m.Parameters.Count == positionalArguments.Count)) { + if (candidate.Parameters.Select(p => p.Type).SequenceEqual(this.PositionalArguments.Select(a => a.Type))) { + ctor = candidate; + break; + } + } + this.constructor = ctor; + } + return ctor; + } + } + + public IList PositionalArguments { + get { return positionalArguments; } + } + + public IList> NamedArguments { + get { return namedArguments; } + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultMemberReference.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultMemberReference.cs new file mode 100644 index 000000000..017302101 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultMemberReference.cs @@ -0,0 +1,118 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// References an entity by its type and name. + /// This class can be used to refer to all members except for constructors and explicit interface implementations. + /// + /// + /// Resolving a DefaultMemberReference requires a context that provides enough information for resolving the declaring type reference + /// and the parameter types references. + /// + [Serializable] + public sealed class DefaultMemberReference : IMemberReference, ISupportsInterning + { + readonly SymbolKind symbolKind; + readonly ITypeReference typeReference; + readonly string name; + readonly int typeParameterCount; + readonly IList parameterTypes; + + public DefaultMemberReference(SymbolKind symbolKind, ITypeReference typeReference, string name, int typeParameterCount = 0, IList parameterTypes = null) + { + if (typeReference == null) + throw new ArgumentNullException("typeReference"); + if (name == null) + throw new ArgumentNullException("name"); + if (typeParameterCount != 0 && symbolKind != SymbolKind.Method) + throw new ArgumentException("Type parameter count > 0 is only supported for methods."); + this.symbolKind = symbolKind; + this.typeReference = typeReference; + this.name = name; + this.typeParameterCount = typeParameterCount; + this.parameterTypes = parameterTypes ?? EmptyList.Instance; + } + + public ITypeReference DeclaringTypeReference { + get { return typeReference; } + } + + public IMember Resolve(ITypeResolveContext context) + { + IType type = typeReference.Resolve(context); + IEnumerable members; + if (symbolKind == SymbolKind.Accessor) { + members = type.GetAccessors( + m => m.Name == name && !m.IsExplicitInterfaceImplementation, + GetMemberOptions.IgnoreInheritedMembers); + } else if (symbolKind == SymbolKind.Method) { + members = type.GetMethods( + m => m.Name == name && m.SymbolKind == SymbolKind.Method + && m.TypeParameters.Count == typeParameterCount && !m.IsExplicitInterfaceImplementation, + GetMemberOptions.IgnoreInheritedMembers); + } else { + members = type.GetMembers( + m => m.Name == name && m.SymbolKind == symbolKind && !m.IsExplicitInterfaceImplementation, + GetMemberOptions.IgnoreInheritedMembers); + } + var resolvedParameterTypes = parameterTypes.Resolve(context); + foreach (IMember member in members) { + IParameterizedMember parameterizedMember = member as IParameterizedMember; + if (parameterizedMember == null) { + if (parameterTypes.Count == 0) + return member; + } else if (parameterTypes.Count == parameterizedMember.Parameters.Count) { + bool signatureMatches = true; + for (int i = 0; i < parameterTypes.Count; i++) { + IType type1 = DummyTypeParameter.NormalizeAllTypeParameters(resolvedParameterTypes[i]); + IType type2 = DummyTypeParameter.NormalizeAllTypeParameters(parameterizedMember.Parameters[i].Type); + if (!type1.Equals(type2)) { + signatureMatches = false; + break; + } + } + if (signatureMatches) + return member; + } + } + return null; + } + + ISymbol ISymbolReference.Resolve(ITypeResolveContext context) + { + return ((IMemberReference)this).Resolve(context); + } + + int ISupportsInterning.GetHashCodeForInterning() + { + return (int)symbolKind ^ typeReference.GetHashCode() ^ name.GetHashCode() ^ parameterTypes.GetHashCode(); + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + DefaultMemberReference o = other as DefaultMemberReference; + return o != null && symbolKind == o.symbolKind && typeReference == o.typeReference && name == o.name && parameterTypes == o.parameterTypes; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultParameter.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultParameter.cs new file mode 100644 index 000000000..9d9565558 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultParameter.cs @@ -0,0 +1,202 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Text; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Default implementation of . + /// + public sealed class DefaultParameter : IParameter + { + readonly IType type; + readonly string name; + readonly DomRegion region; + readonly IList attributes; + readonly bool isRef, isOut, isParams, isOptional; + readonly object defaultValue; + readonly IParameterizedMember owner; + + public DefaultParameter(IType type, string name) + { + if (type == null) + throw new ArgumentNullException("type"); + if (name == null) + throw new ArgumentNullException("name"); + this.type = type; + this.name = name; + } + + public DefaultParameter(IType type, string name, IParameterizedMember owner = null, DomRegion region = default(DomRegion), IList attributes = null, + bool isRef = false, bool isOut = false, bool isParams = false, bool isOptional = false, object defaultValue = null) + { + if (type == null) + throw new ArgumentNullException("type"); + if (name == null) + throw new ArgumentNullException("name"); + this.type = type; + this.name = name; + this.owner = owner; + this.region = region; + this.attributes = attributes; + this.isRef = isRef; + this.isOut = isOut; + this.isParams = isParams; + this.isOptional = isOptional; + this.defaultValue = defaultValue; + } + + SymbolKind ISymbol.SymbolKind { + get { return SymbolKind.Parameter; } + } + + public IParameterizedMember Owner { + get { return owner; } + } + + public IList Attributes { + get { return attributes; } + } + + public bool IsRef { + get { return isRef; } + } + + public bool IsOut { + get { return isOut; } + } + + public bool IsParams { + get { return isParams; } + } + + public bool IsOptional { + get { return isOptional; } + } + + public string Name { + get { return name; } + } + + public DomRegion Region { + get { return region; } + } + + public IType Type { + get { return type; } + } + + bool IVariable.IsConst { + get { return false; } + } + + public object ConstantValue { + get { return defaultValue; } + } + + public override string ToString() + { + return ToString(this); + } + + public static string ToString(IParameter parameter) + { + StringBuilder b = new StringBuilder(); + if (parameter.IsRef) + b.Append("ref "); + if (parameter.IsOut) + b.Append("out "); + if (parameter.IsParams) + b.Append("params "); + b.Append(parameter.Name); + b.Append(':'); + b.Append(parameter.Type.ReflectionName); + if (parameter.IsOptional) { + b.Append(" = "); + if (parameter.ConstantValue != null) + b.Append(parameter.ConstantValue.ToString()); + else + b.Append("null"); + } + return b.ToString(); + } + + public ISymbolReference ToReference() + { + if (owner == null) + return new ParameterReference(type.ToTypeReference(), name, region, isRef, isOut, isParams, isOptional, defaultValue); + return new OwnedParameterReference(owner.ToReference(), owner.Parameters.IndexOf(this)); + } + } + + sealed class OwnedParameterReference : ISymbolReference + { + readonly IMemberReference memberReference; + readonly int index; + + public OwnedParameterReference(IMemberReference member, int index) + { + if (member == null) + throw new ArgumentNullException("member"); + this.memberReference = member; + this.index = index; + } + + public ISymbol Resolve(ITypeResolveContext context) + { + IParameterizedMember member = memberReference.Resolve(context) as IParameterizedMember; + if (member != null && index >= 0 && index < member.Parameters.Count) + return member.Parameters[index]; + else + return null; + } + } + + public sealed class ParameterReference : ISymbolReference + { + readonly ITypeReference type; + readonly string name; + readonly DomRegion region; + readonly bool isRef, isOut, isParams, isOptional; + readonly object defaultValue; + + public ParameterReference(ITypeReference type, string name, DomRegion region, bool isRef, bool isOut, bool isParams, bool isOptional, object defaultValue) + { + if (type == null) + throw new ArgumentNullException("type"); + if (name == null) + throw new ArgumentNullException("name"); + this.type = type; + this.name = name; + this.region = region; + this.isRef = isRef; + this.isOut = isOut; + this.isParams = isParams; + this.isOptional = isOptional; + this.defaultValue = defaultValue; + } + + public ISymbol Resolve(ITypeResolveContext context) + { + return new DefaultParameter(type.Resolve(context), name, region: region, isRef: isRef, isOut: isOut, isParams: isParams, isOptional: isOptional, defaultValue: defaultValue); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedEvent.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedEvent.cs new file mode 100644 index 000000000..2335b788a --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedEvent.cs @@ -0,0 +1,75 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + public class DefaultResolvedEvent : AbstractResolvedMember, IEvent + { + protected new readonly IUnresolvedEvent unresolved; + IMethod addAccessor; + IMethod removeAccessor; + IMethod invokeAccessor; + + public DefaultResolvedEvent(IUnresolvedEvent unresolved, ITypeResolveContext parentContext) + : base(unresolved, parentContext) + { + this.unresolved = unresolved; + } + + public bool CanAdd { + get { return unresolved.CanAdd; } + } + + public bool CanRemove { + get { return unresolved.CanRemove; } + } + + public bool CanInvoke { + get { return unresolved.CanInvoke; } + } + + public IMethod AddAccessor { + get { return GetAccessor(ref addAccessor, unresolved.AddAccessor); } + } + + public IMethod RemoveAccessor { + get { return GetAccessor(ref removeAccessor, unresolved.RemoveAccessor); } + } + + public IMethod InvokeAccessor { + get { return GetAccessor(ref invokeAccessor, unresolved.InvokeAccessor); } + } + + public override IMember Specialize(TypeParameterSubstitution substitution) + { + if (TypeParameterSubstitution.Identity.Equals(substitution) + || DeclaringTypeDefinition == null + || DeclaringTypeDefinition.TypeParameterCount == 0) + { + return this; + } + if (substitution.MethodTypeArguments != null && substitution.MethodTypeArguments.Count > 0) + substitution = new TypeParameterSubstitution(substitution.ClassTypeArguments, EmptyList.Instance); + return new SpecializedEvent(this, substitution); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedField.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedField.cs new file mode 100644 index 000000000..16981d2b7 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedField.cs @@ -0,0 +1,93 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Semantics; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + public class DefaultResolvedField : AbstractResolvedMember, IField + { + volatile ResolveResult constantValue; + + public DefaultResolvedField(IUnresolvedField unresolved, ITypeResolveContext parentContext) + : base(unresolved, parentContext) + { + } + + public bool IsReadOnly { + get { return ((IUnresolvedField)unresolved).IsReadOnly; } + } + + public bool IsVolatile { + get { return ((IUnresolvedField)unresolved).IsVolatile; } + } + + IType IVariable.Type { + get { return this.ReturnType; } + } + + public bool IsConst { + get { return ((IUnresolvedField)unresolved).IsConst; } + } + + public bool IsFixed { + get { return ((IUnresolvedField)unresolved).IsFixed; } + } + + public object ConstantValue { + get { + ResolveResult rr = this.constantValue; + if (rr == null) { + using (var busyLock = BusyManager.Enter(this)) { + if (!busyLock.Success) + return null; + + IConstantValue unresolvedCV = ((IUnresolvedField)unresolved).ConstantValue; + if (unresolvedCV != null) + rr = unresolvedCV.Resolve(context); + else + rr = ErrorResolveResult.UnknownError; + this.constantValue = rr; + } + } + return rr.ConstantValue; + } + } + + public override IMember Specialize(TypeParameterSubstitution substitution) + { + if (TypeParameterSubstitution.Identity.Equals(substitution) + || DeclaringTypeDefinition == null + || DeclaringTypeDefinition.TypeParameterCount == 0) + { + return this; + } + if (substitution.MethodTypeArguments != null && substitution.MethodTypeArguments.Count > 0) + substitution = new TypeParameterSubstitution(substitution.ClassTypeArguments, EmptyList.Instance); + return new SpecializedField(this, substitution); + } + + IMemberReference IField.ToReference() + { + return (IMemberReference)ToReference(); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedMethod.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedMethod.cs new file mode 100644 index 000000000..0dc9bcc54 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedMethod.cs @@ -0,0 +1,327 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; +using System.Text; + +using ICSharpCode.NRefactory.Semantics; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Default implementation of that resolves an unresolved method. + /// + public class DefaultResolvedMethod : AbstractResolvedMember, IMethod + { + IUnresolvedMethod[] parts; + + public DefaultResolvedMethod(DefaultUnresolvedMethod unresolved, ITypeResolveContext parentContext) + : this(unresolved, parentContext, unresolved.IsExtensionMethod) + { + } + + public DefaultResolvedMethod(IUnresolvedMethod unresolved, ITypeResolveContext parentContext, bool isExtensionMethod) + : base(unresolved, parentContext) + { + this.Parameters = unresolved.Parameters.CreateResolvedParameters(context); + this.ReturnTypeAttributes = unresolved.ReturnTypeAttributes.CreateResolvedAttributes(parentContext); + this.TypeParameters = unresolved.TypeParameters.CreateResolvedTypeParameters(context); + this.IsExtensionMethod = isExtensionMethod; + } + + class ListOfLists : IList + { + List> lists =new List> (); + + public void AddList(IList list) + { + lists.Add (list); + } + + #region IEnumerable implementation + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + #endregion + + #region IEnumerable implementation + public IEnumerator GetEnumerator () + { + for (int i = 0; i < this.Count; i++) { + yield return this[i]; + } + } + #endregion + + #region ICollection implementation + public void Add (T item) + { + throw new NotSupportedException(); + } + + public void Clear () + { + throw new NotSupportedException(); + } + + public bool Contains (T item) + { + var comparer = EqualityComparer.Default; + for (int i = 0; i < this.Count; i++) { + if (comparer.Equals(this[i], item)) + return true; + } + return false; + } + + public void CopyTo (T[] array, int arrayIndex) + { + for (int i = 0; i < Count; i++) { + array[arrayIndex + i] = this[i]; + } + } + + public bool Remove (T item) + { + throw new NotSupportedException(); + } + + public int Count { + get { + return lists.Sum (l => l.Count); + } + } + + public bool IsReadOnly { + get { + return true; + } + } + #endregion + + #region IList implementation + public int IndexOf (T item) + { + var comparer = EqualityComparer.Default; + for (int i = 0; i < this.Count; i++) { + if (comparer.Equals(this[i], item)) + return i; + } + return -1; + } + + public void Insert (int index, T item) + { + throw new NotSupportedException(); + } + + public void RemoveAt (int index) + { + throw new NotSupportedException(); + } + + public T this[int index] { + get { + foreach (var list in lists){ + if (index < list.Count) + return list[index]; + index -= list.Count; + } + throw new IndexOutOfRangeException (); + } + set { + throw new NotSupportedException(); + } + } + #endregion + } + + public static DefaultResolvedMethod CreateFromMultipleParts(IUnresolvedMethod[] parts, ITypeResolveContext[] contexts, bool isExtensionMethod) + { + DefaultResolvedMethod method = new DefaultResolvedMethod(parts[0], contexts[0], isExtensionMethod); + method.parts = parts; + if (parts.Length > 1) { + var attrs = new ListOfLists (); + attrs.AddList (method.Attributes); + for (int i = 1; i < parts.Length; i++) { + attrs.AddList (parts[i].Attributes.CreateResolvedAttributes(contexts[i])); + } + method.Attributes = attrs; + } + return method; + } + + public IList Parameters { get; private set; } + public IList ReturnTypeAttributes { get; private set; } + public IList TypeParameters { get; private set; } + + public IList TypeArguments { + get { + // ToList() call is necessary because IList<> isn't covariant + return TypeParameters.ToList(); + } + } + + bool IMethod.IsParameterized { + get { return false; } + } + + public bool IsExtensionMethod { get; private set; } + + public IList Parts { + get { + return parts ?? new IUnresolvedMethod[] { (IUnresolvedMethod)unresolved }; + } + } + + public bool IsConstructor { + get { return ((IUnresolvedMethod)unresolved).IsConstructor; } + } + + public bool IsDestructor { + get { return ((IUnresolvedMethod)unresolved).IsDestructor; } + } + + public bool IsOperator { + get { return ((IUnresolvedMethod)unresolved).IsOperator; } + } + + public bool IsPartial { + get { return ((IUnresolvedMethod)unresolved).IsPartial; } + } + + public bool IsAsync { + get { return ((IUnresolvedMethod)unresolved).IsAsync; } + } + + public bool HasBody { + get { return ((IUnresolvedMethod)unresolved).HasBody; } + } + + public bool IsAccessor { + get { return ((IUnresolvedMethod)unresolved).AccessorOwner != null; } + } + + IMethod IMethod.ReducedFrom { + get { return null; } + } + + public virtual IMember AccessorOwner { + get { + var reference = ((IUnresolvedMethod)unresolved).AccessorOwner; + if (reference != null) + return reference.Resolve(context); + else + return null; + } + } + + public override ISymbolReference ToReference() + { + var declType = this.DeclaringType; + var declTypeRef = declType != null ? declType.ToTypeReference() : SpecialType.UnknownType; + if (IsExplicitInterfaceImplementation && ImplementedInterfaceMembers.Count == 1) { + return new ExplicitInterfaceImplementationMemberReference(declTypeRef, ImplementedInterfaceMembers[0].ToReference()); + } else { + return new DefaultMemberReference( + this.SymbolKind, declTypeRef, this.Name, this.TypeParameters.Count, + this.Parameters.Select(p => p.Type.ToTypeReference()).ToList()); + } + } + + public override IMemberReference ToMemberReference() + { + return (IMemberReference)ToReference(); + } + + public override IMember Specialize(TypeParameterSubstitution substitution) + { + if (TypeParameterSubstitution.Identity.Equals(substitution)) + return this; + if (TypeParameters.Count == 0) { + if (DeclaringTypeDefinition == null || DeclaringTypeDefinition.TypeParameterCount == 0) + return this; + if (substitution.MethodTypeArguments != null && substitution.MethodTypeArguments.Count > 0) + substitution = new TypeParameterSubstitution(substitution.ClassTypeArguments, EmptyList.Instance); + } + return new SpecializedMethod(this, substitution); + } + + IMethod IMethod.Specialize(TypeParameterSubstitution substitution) + { + return (IMethod)Specialize(substitution); + } + + public override string ToString() + { + StringBuilder b = new StringBuilder("["); + b.Append(this.SymbolKind); + b.Append(' '); + if (this.DeclaringType != null) { + 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(); + } + + /// + /// Gets a dummy constructor for the specified compilation. + /// + /// + /// A public instance constructor with IsSynthetic=true and no declaring type. + /// + /// + public static IMethod GetDummyConstructor(ICompilation compilation) + { + var dummyConstructor = DefaultUnresolvedMethod.DummyConstructor; + // Reuse the same IMethod instance for all dummy constructors + // so that two occurrences of 'new T()' refer to the same constructor. + return (IMethod)compilation.CacheManager.GetOrAddShared( + dummyConstructor, _ => dummyConstructor.CreateResolved(compilation.TypeResolveContext)); + } + + /// + /// Gets a dummy constructor for the specified type. + /// + /// + /// A public instance constructor with IsSynthetic=true and the specified declaring type. + /// + /// + public static IMethod GetDummyConstructor(ICompilation compilation, IType declaringType) + { + var resolvedCtor = GetDummyConstructor(compilation); + return new SpecializedMethod(resolvedCtor, TypeParameterSubstitution.Identity) { DeclaringType = declaringType }; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedProperty.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedProperty.cs new file mode 100644 index 000000000..69b477f8e --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedProperty.cs @@ -0,0 +1,114 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + public class DefaultResolvedProperty : AbstractResolvedMember, IProperty + { + protected new readonly IUnresolvedProperty unresolved; + readonly IList parameters; + IMethod getter; + IMethod setter; + const Accessibility InvalidAccessibility = (Accessibility)0xff; + volatile Accessibility cachedAccessiblity = InvalidAccessibility; + + public DefaultResolvedProperty(IUnresolvedProperty unresolved, ITypeResolveContext parentContext) + : base(unresolved, parentContext) + { + this.unresolved = unresolved; + this.parameters = unresolved.Parameters.CreateResolvedParameters(context); + } + + public IList Parameters { + get { return parameters; } + } + + public override Accessibility Accessibility { + get { + var acc = cachedAccessiblity; + if (acc == InvalidAccessibility) + return cachedAccessiblity = ComputeAccessibility(); + else + return acc; + } + } + + Accessibility ComputeAccessibility() + { + var baseAcc = base.Accessibility; + if (IsOverride && !(CanGet && CanSet)) { + foreach (var baseMember in InheritanceHelper.GetBaseMembers(this, false)) { + if (!baseMember.IsOverride) + return baseMember.Accessibility; + } + } + return baseAcc; + } + + public bool CanGet { + get { return unresolved.CanGet; } + } + + public bool CanSet { + get { return unresolved.CanSet; } + } + + public IMethod Getter { + get { return GetAccessor(ref getter, unresolved.Getter); } + } + + public IMethod Setter { + get { return GetAccessor(ref setter, unresolved.Setter); } + } + + public bool IsIndexer { + get { return unresolved.IsIndexer; } + } + + public override ISymbolReference ToReference() + { + var declType = this.DeclaringType; + var declTypeRef = declType != null ? declType.ToTypeReference() : SpecialType.UnknownType; + if (IsExplicitInterfaceImplementation && ImplementedInterfaceMembers.Count == 1) { + return new ExplicitInterfaceImplementationMemberReference(declTypeRef, ImplementedInterfaceMembers[0].ToReference()); + } else { + return new DefaultMemberReference( + this.SymbolKind, declTypeRef, this.Name, 0, + this.Parameters.Select(p => p.Type.ToTypeReference()).ToList()); + } + } + + public override IMember Specialize(TypeParameterSubstitution substitution) + { + if (TypeParameterSubstitution.Identity.Equals(substitution) + || DeclaringTypeDefinition == null + || DeclaringTypeDefinition.TypeParameterCount == 0) + { + return this; + } + if (substitution.MethodTypeArguments != null && substitution.MethodTypeArguments.Count > 0) + substitution = new TypeParameterSubstitution(substitution.ClassTypeArguments, EmptyList.Instance); + return new SpecializedProperty(this, substitution); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs new file mode 100644 index 000000000..80b332d85 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs @@ -0,0 +1,963 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; +using ICSharpCode.NRefactory.Documentation; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Default implementation of . + /// + public class DefaultResolvedTypeDefinition : ITypeDefinition + { + readonly ITypeResolveContext parentContext; + readonly IUnresolvedTypeDefinition[] parts; + Accessibility accessibility = Accessibility.Internal; + bool isAbstract, isSealed, isShadowing; + bool isSynthetic = true; // true if all parts are synthetic + + public DefaultResolvedTypeDefinition(ITypeResolveContext parentContext, params IUnresolvedTypeDefinition[] parts) + { + if (parentContext == null || parentContext.CurrentAssembly == null) + throw new ArgumentException("Parent context does not specify any assembly", "parentContext"); + if (parts == null || parts.Length == 0) + throw new ArgumentException("No parts were specified", "parts"); + this.parentContext = parentContext; + this.parts = parts; + + foreach (IUnresolvedTypeDefinition part in parts) { + isAbstract |= part.IsAbstract; + isSealed |= part.IsSealed; + isShadowing |= part.IsShadowing; + isSynthetic &= part.IsSynthetic; // true if all parts are synthetic + + // internal is the default, so use another part's accessibility until we find a non-internal accessibility + if (accessibility == Accessibility.Internal) + accessibility = part.Accessibility; + } + } + + IList typeParameters; + + public IList TypeParameters { + get { + var result = LazyInit.VolatileRead(ref this.typeParameters); + if (result != null) { + return result; + } + ITypeResolveContext contextForTypeParameters = parts[0].CreateResolveContext(parentContext); + contextForTypeParameters = contextForTypeParameters.WithCurrentTypeDefinition(this); + if (parentContext.CurrentTypeDefinition == null || parentContext.CurrentTypeDefinition.TypeParameterCount == 0) { + result = parts[0].TypeParameters.CreateResolvedTypeParameters(contextForTypeParameters); + } else { + // This is a nested class inside a generic class; copy type parameters from outer class if we can: + var outerClass = parentContext.CurrentTypeDefinition; + ITypeParameter[] typeParameters = new ITypeParameter[parts[0].TypeParameters.Count]; + for (int i = 0; i < typeParameters.Length; i++) { + var unresolvedTP = parts[0].TypeParameters[i]; + if (i < outerClass.TypeParameterCount && outerClass.TypeParameters[i].Name == unresolvedTP.Name) + typeParameters[i] = outerClass.TypeParameters[i]; + else + typeParameters[i] = unresolvedTP.CreateResolvedTypeParameter(contextForTypeParameters); + } + result = Array.AsReadOnly(typeParameters); + } + return LazyInit.GetOrSet(ref this.typeParameters, result); + } + } + + IList attributes; + + public IList Attributes { + get { + var result = LazyInit.VolatileRead(ref this.attributes); + if (result != null) { + return result; + } + result = new List(); + var context = parentContext.WithCurrentTypeDefinition(this); + foreach (IUnresolvedTypeDefinition part in parts) { + ITypeResolveContext parentContextForPart = part.CreateResolveContext(context); + foreach (var attr in part.Attributes) { + result.Add(attr.CreateResolvedAttribute(parentContextForPart)); + } + } + if (result.Count == 0) + result = EmptyList.Instance; + return LazyInit.GetOrSet(ref this.attributes, result); + } + } + + public IList Parts { + get { return parts; } + } + + public SymbolKind SymbolKind { + get { return parts[0].SymbolKind; } + } + + [Obsolete("Use the SymbolKind property instead.")] + public EntityType EntityType { + get { return (EntityType)parts[0].SymbolKind; } + } + + public virtual TypeKind Kind { + get { return parts[0].Kind; } + } + + #region NestedTypes + IList nestedTypes; + + public IList NestedTypes { + get { + IList result = LazyInit.VolatileRead(ref this.nestedTypes); + if (result != null) { + return result; + } else { + result = ( + from part in parts + from nestedTypeRef in part.NestedTypes + group nestedTypeRef by new { nestedTypeRef.Name, nestedTypeRef.TypeParameters.Count } into g + select new DefaultResolvedTypeDefinition(new SimpleTypeResolveContext(this), g.ToArray()) + ).ToList().AsReadOnly(); + return LazyInit.GetOrSet(ref this.nestedTypes, result); + } + } + } + #endregion + + #region Members + sealed class MemberList : IList + { + internal readonly ITypeResolveContext[] contextPerMember; + internal readonly IUnresolvedMember[] unresolvedMembers; + internal readonly IMember[] resolvedMembers; + internal readonly int NonPartialMemberCount; + + public MemberList(List contextPerMember, List unresolvedNonPartialMembers, List partialMethodInfos) + { + this.NonPartialMemberCount = unresolvedNonPartialMembers.Count; + this.contextPerMember = contextPerMember.ToArray(); + this.unresolvedMembers = unresolvedNonPartialMembers.ToArray(); + if (partialMethodInfos == null) { + this.resolvedMembers = new IMember[unresolvedNonPartialMembers.Count]; + } else { + this.resolvedMembers = new IMember[unresolvedNonPartialMembers.Count + partialMethodInfos.Count]; + for (int i = 0; i < partialMethodInfos.Count; i++) { + var info = partialMethodInfos[i]; + int memberIndex = NonPartialMemberCount + i; + resolvedMembers[memberIndex] = DefaultResolvedMethod.CreateFromMultipleParts( + info.Parts.ToArray(), info.Contexts.ToArray (), false); + } + } + } + + public IMember this[int index] { + get { + IMember output = LazyInit.VolatileRead(ref resolvedMembers[index]); + if (output != null) { + return output; + } + return LazyInit.GetOrSet(ref resolvedMembers[index], unresolvedMembers[index].CreateResolved(contextPerMember[index])); + } + set { throw new NotSupportedException(); } + } + + public int Count { + get { return resolvedMembers.Length; } + } + + bool ICollection.IsReadOnly { + get { return true; } + } + + public int IndexOf(IMember item) + { + for (int i = 0; i < this.Count; i++) { + if (this[i].Equals(item)) + return i; + } + return -1; + } + + void IList.Insert(int index, IMember item) + { + throw new NotSupportedException(); + } + + void IList.RemoveAt(int index) + { + throw new NotSupportedException(); + } + + void ICollection.Add(IMember item) + { + throw new NotSupportedException(); + } + + void ICollection.Clear() + { + throw new NotSupportedException(); + } + + bool ICollection.Contains(IMember item) + { + return IndexOf(item) >= 0; + } + + void ICollection.CopyTo(IMember[] array, int arrayIndex) + { + for (int i = 0; i < this.Count; i++) { + array[arrayIndex + i] = this[i]; + } + } + + bool ICollection.Remove(IMember item) + { + throw new NotSupportedException(); + } + + public IEnumerator GetEnumerator() + { + for (int i = 0; i < this.Count; i++) { + yield return this[i]; + } + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + + sealed class PartialMethodInfo + { + public readonly string Name; + public readonly int TypeParameterCount; + public readonly IList Parameters; + public readonly List Parts = new List(); + public readonly List Contexts = new List(); + + public PartialMethodInfo(IUnresolvedMethod method, ITypeResolveContext context) + { + this.Name = method.Name; + this.TypeParameterCount = method.TypeParameters.Count; + this.Parameters = method.Parameters.CreateResolvedParameters(context); + this.Parts.Add(method); + this.Contexts.Add (context); + } + + public void AddPart(IUnresolvedMethod method, ITypeResolveContext context) + { + if (method.HasBody) { + // make the implementation the primary part + this.Parts.Insert(0, method); + this.Contexts.Insert (0, context); + } else { + this.Parts.Add(method); + this.Contexts.Add (context); + } + } + + public bool IsSameSignature(PartialMethodInfo other, StringComparer nameComparer) + { + return nameComparer.Equals(this.Name, other.Name) + && this.TypeParameterCount == other.TypeParameterCount + && ParameterListComparer.Instance.Equals(this.Parameters, other.Parameters); + } + } + + MemberList memberList; + + MemberList GetMemberList() + { + var result = LazyInit.VolatileRead(ref this.memberList); + if (result != null) { + return result; + } + List unresolvedMembers = new List(); + List contextPerMember = new List(); + List partialMethodInfos = null; + bool addDefaultConstructorIfRequired = false; + foreach (IUnresolvedTypeDefinition part in parts) { + ITypeResolveContext parentContextForPart = part.CreateResolveContext(parentContext); + ITypeResolveContext contextForPart = parentContextForPart.WithCurrentTypeDefinition(this); + foreach (var member in part.Members) { + IUnresolvedMethod method = member as IUnresolvedMethod; + if (method != null && method.IsPartial) { + // Merge partial method declaration and implementation + if (partialMethodInfos == null) + partialMethodInfos = new List(); + PartialMethodInfo newInfo = new PartialMethodInfo(method, contextForPart); + PartialMethodInfo existingInfo = null; + foreach (var info in partialMethodInfos) { + if (newInfo.IsSameSignature(info, Compilation.NameComparer)) { + existingInfo = info; + break; + } + } + if (existingInfo != null) { + // Add the unresolved method to the PartialMethodInfo: + existingInfo.AddPart(method, contextForPart); + } else { + partialMethodInfos.Add(newInfo); + } + } else { + unresolvedMembers.Add(member); + contextPerMember.Add(contextForPart); + } + } + + addDefaultConstructorIfRequired |= part.AddDefaultConstructorIfRequired; + } + if (addDefaultConstructorIfRequired) { + TypeKind kind = this.Kind; + if (kind == TypeKind.Class && !this.IsStatic && !unresolvedMembers.Any(m => m.SymbolKind == SymbolKind.Constructor && !m.IsStatic) + || kind == TypeKind.Enum || kind == TypeKind.Struct) + { + contextPerMember.Add(parts[0].CreateResolveContext(parentContext).WithCurrentTypeDefinition(this)); + unresolvedMembers.Add(DefaultUnresolvedMethod.CreateDefaultConstructor(parts[0])); + } + } + result = new MemberList(contextPerMember, unresolvedMembers, partialMethodInfos); + return LazyInit.GetOrSet(ref this.memberList, result); + } + + public IList Members { + get { return GetMemberList(); } + } + + public IEnumerable Fields { + get { + var members = GetMemberList(); + for (int i = 0; i < members.unresolvedMembers.Length; i++) { + if (members.unresolvedMembers[i].SymbolKind == SymbolKind.Field) + yield return (IField)members[i]; + } + } + } + + public IEnumerable Methods { + get { + var members = GetMemberList(); + for (int i = 0; i < members.unresolvedMembers.Length; i++) { + if (members.unresolvedMembers[i] is IUnresolvedMethod) + yield return (IMethod)members[i]; + } + for (int i = members.unresolvedMembers.Length; i < members.Count; i++) { + yield return (IMethod)members[i]; + } + } + } + + public IEnumerable Properties { + get { + var members = GetMemberList(); + for (int i = 0; i < members.unresolvedMembers.Length; i++) { + switch (members.unresolvedMembers[i].SymbolKind) { + case SymbolKind.Property: + case SymbolKind.Indexer: + yield return (IProperty)members[i]; + break; + } + } + } + } + + public IEnumerable Events { + get { + var members = GetMemberList(); + for (int i = 0; i < members.unresolvedMembers.Length; i++) { + if (members.unresolvedMembers[i].SymbolKind == SymbolKind.Event) + yield return (IEvent)members[i]; + } + } + } + #endregion + + volatile KnownTypeCode knownTypeCode = (KnownTypeCode)(-1); + + public KnownTypeCode KnownTypeCode { + get { + KnownTypeCode result = this.knownTypeCode; + if (result == (KnownTypeCode)(-1)) { + result = KnownTypeCode.None; + ICompilation compilation = this.Compilation; + for (int i = 0; i < KnownTypeReference.KnownTypeCodeCount; i++) { + if (compilation.FindType((KnownTypeCode)i) == this) { + result = (KnownTypeCode)i; + break; + } + } + this.knownTypeCode = result; + } + return result; + } + } + + volatile IType enumUnderlyingType; + + public IType EnumUnderlyingType { + get { + IType result = this.enumUnderlyingType; + if (result == null) { + if (this.Kind == TypeKind.Enum) { + result = CalculateEnumUnderlyingType(); + } else { + result = SpecialType.UnknownType; + } + this.enumUnderlyingType = result; + } + return result; + } + } + + IType CalculateEnumUnderlyingType() + { + foreach (var part in parts) { + var context = part.CreateResolveContext(parentContext).WithCurrentTypeDefinition(this); + foreach (var baseTypeRef in part.BaseTypes) { + IType type = baseTypeRef.Resolve(context); + if (type.Kind != TypeKind.Unknown) + return type; + } + } + return this.Compilation.FindType(KnownTypeCode.Int32); + } + + volatile byte hasExtensionMethods; // 0 = unknown, 1 = true, 2 = false + + public bool HasExtensionMethods { + get { + byte val = this.hasExtensionMethods; + if (val == 0) { + if (CalculateHasExtensionMethods()) + val = 1; + else + val = 2; + this.hasExtensionMethods = val; + } + return val == 1; + } + } + + bool CalculateHasExtensionMethods() + { + bool noExtensionMethods = true; + foreach (var part in parts) { + // Return true if any part has extension methods + if (part.HasExtensionMethods == true) + return true; + if (part.HasExtensionMethods == null) + noExtensionMethods = false; + } + // Return false if all parts are known to have no extension methods + if (noExtensionMethods) + return false; + // If unsure, look at the resolved methods. + return Methods.Any(m => m.IsExtensionMethod); + } + + public bool IsPartial { + get { return parts.Length > 1 || parts[0].IsPartial; } + } + + public bool? IsReferenceType { + get { + switch (this.Kind) { + case TypeKind.Class: + case TypeKind.Interface: + case TypeKind.Module: + case TypeKind.Delegate: + return true; + case TypeKind.Struct: + case TypeKind.Enum: + case TypeKind.Void: + return false; + default: + throw new InvalidOperationException("Invalid value for TypeKind"); + } + } + } + + public int TypeParameterCount { + get { return parts[0].TypeParameters.Count; } + } + + public IList TypeArguments { + get { + // ToList() call is necessary because IList<> isn't covariant + return TypeParameters.ToList(); + } + } + + public bool IsParameterized { + get { return false; } + } + + #region DirectBaseTypes + IList directBaseTypes; + + public IEnumerable DirectBaseTypes { + get { + IList result = LazyInit.VolatileRead(ref this.directBaseTypes); + if (result != null) { + return result; + } + using (var busyLock = BusyManager.Enter(this)) { + if (busyLock.Success) { + result = CalculateDirectBaseTypes(); + return LazyInit.GetOrSet(ref this.directBaseTypes, result); + } else { + // This can happen for "class Test : $Test.Base$ { public class Base {} }" + // and also for the valid code + // "class Test : Base { public class Inner {} }" + + // Don't cache the error! + return EmptyList.Instance; + } + } + } + } + + IList CalculateDirectBaseTypes() + { + List result = new List(); + bool hasNonInterface = false; + if (this.Kind != TypeKind.Enum) { + foreach (var part in parts) { + var context = part.CreateResolveContext(parentContext).WithCurrentTypeDefinition(this); + foreach (var baseTypeRef in part.BaseTypes) { + IType baseType = baseTypeRef.Resolve(context); + if (!(baseType.Kind == TypeKind.Unknown || result.Contains(baseType))) { + result.Add(baseType); + if (baseType.Kind != TypeKind.Interface) + hasNonInterface = true; + } + } + } + } + if (!hasNonInterface && !(this.Name == "Object" && this.Namespace == "System" && this.TypeParameterCount == 0)) { + KnownTypeCode primitiveBaseType; + switch (this.Kind) { + case TypeKind.Enum: + primitiveBaseType = KnownTypeCode.Enum; + break; + case TypeKind.Struct: + case TypeKind.Void: + primitiveBaseType = KnownTypeCode.ValueType; + break; + case TypeKind.Delegate: + primitiveBaseType = KnownTypeCode.Delegate; + break; + default: + primitiveBaseType = KnownTypeCode.Object; + break; + } + IType t = parentContext.Compilation.FindType(primitiveBaseType); + if (t.Kind != TypeKind.Unknown) + result.Add(t); + } + return result; + } + #endregion + + public string FullName { + get { return parts[0].FullName; } + } + + public string Name { + get { return parts[0].Name; } + } + + public string ReflectionName { + get { return parts[0].ReflectionName; } + } + + public string Namespace { + get { return parts[0].Namespace; } + } + + public FullTypeName FullTypeName { + get { return parts[0].FullTypeName; } + } + + public DomRegion Region { + get { return parts[0].Region; } + } + + public DomRegion BodyRegion { + get { return parts[0].BodyRegion; } + } + + public ITypeDefinition DeclaringTypeDefinition { + get { return parentContext.CurrentTypeDefinition; } + } + + public IType DeclaringType { + get { return parentContext.CurrentTypeDefinition; } + } + + public IAssembly ParentAssembly { + get { return parentContext.CurrentAssembly; } + } + + public virtual DocumentationComment Documentation { + get { + foreach (var part in parts) { + var unresolvedProvider = part.UnresolvedFile as IUnresolvedDocumentationProvider; + if (unresolvedProvider != null) { + var doc = unresolvedProvider.GetDocumentation(part, this); + if (doc != null) + return doc; + } + } + IDocumentationProvider provider = AbstractResolvedEntity.FindDocumentation(parentContext); + if (provider != null) + return provider.GetDocumentation(this); + else + return null; + } + } + + public ICompilation Compilation { + get { return parentContext.Compilation; } + } + + #region Modifiers + public bool IsStatic { get { return isAbstract && isSealed; } } + public bool IsAbstract { get { return isAbstract; } } + public bool IsSealed { get { return isSealed; } } + public bool IsShadowing { get { return isShadowing; } } + public bool IsSynthetic { get { return isSynthetic; } } + + public Accessibility Accessibility { + get { return accessibility; } + } + + bool IHasAccessibility.IsPrivate { + get { return accessibility == Accessibility.Private; } + } + + bool IHasAccessibility.IsPublic { + get { return accessibility == Accessibility.Public; } + } + + bool IHasAccessibility.IsProtected { + get { return accessibility == Accessibility.Protected; } + } + + bool IHasAccessibility.IsInternal { + get { return accessibility == Accessibility.Internal; } + } + + bool IHasAccessibility.IsProtectedOrInternal { + get { return accessibility == Accessibility.ProtectedOrInternal; } + } + + bool IHasAccessibility.IsProtectedAndInternal { + get { return accessibility == Accessibility.ProtectedAndInternal; } + } + #endregion + + ITypeDefinition IType.GetDefinition() + { + return this; + } + + IType IType.AcceptVisitor(TypeVisitor visitor) + { + return visitor.VisitTypeDefinition(this); + } + + IType IType.VisitChildren(TypeVisitor visitor) + { + return this; + } + + public ITypeReference ToTypeReference() + { + ITypeDefinition declTypeDef = this.DeclaringTypeDefinition; + if (declTypeDef != null) { + return new NestedTypeReference(declTypeDef.ToTypeReference(), this.Name, this.TypeParameterCount - declTypeDef.TypeParameterCount); + } else { + IAssembly asm = this.ParentAssembly; + IAssemblyReference asmRef; + if (asm != null) + asmRef = new DefaultAssemblyReference(asm.AssemblyName); + else + asmRef = null; + return new GetClassTypeReference(asmRef, this.Namespace, this.Name, this.TypeParameterCount); + } + } + + ISymbolReference ISymbol.ToReference() + { + return (ISymbolReference)ToTypeReference(); + } + + public IEnumerable GetNestedTypes(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + const GetMemberOptions opt = GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions; + if ((options & opt) == opt) { + if (filter == null) + return this.NestedTypes; + else + return GetNestedTypesImpl(filter); + } else { + return GetMembersHelper.GetNestedTypes(this, filter, options); + } + } + + IEnumerable GetNestedTypesImpl(Predicate filter) + { + foreach (var nestedType in this.NestedTypes) { + if (filter(nestedType)) + yield return nestedType; + } + } + + public IEnumerable GetNestedTypes(IList typeArguments, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + return GetMembersHelper.GetNestedTypes(this, typeArguments, filter, options); + } + + #region GetMembers() + IEnumerable GetFilteredMembers(Predicate filter) + { + var members = GetMemberList(); + for (int i = 0; i < members.unresolvedMembers.Length; i++) { + if (filter == null || filter(members.unresolvedMembers[i])) { + yield return members[i]; + } + } + for (int i = members.unresolvedMembers.Length; i < members.Count; i++) { + var method = (IMethod)members[i]; + bool ok = false; + foreach (var part in method.Parts) { + if (filter == null || filter(part)) { + ok = true; + break; + } + } + if (ok) + yield return method; + } + } + + IEnumerable GetFilteredMethods(Predicate filter) + { + var members = GetMemberList(); + for (int i = 0; i < members.unresolvedMembers.Length; i++) { + IUnresolvedMethod unresolved = members.unresolvedMembers[i] as IUnresolvedMethod; + if (unresolved != null && (filter == null || filter(unresolved))) { + yield return (IMethod)members[i]; + } + } + for (int i = members.unresolvedMembers.Length; i < members.Count; i++) { + var method = (IMethod)members[i]; + bool ok = false; + foreach (var part in method.Parts) { + if (filter == null || filter(part)) { + ok = true; + break; + } + } + if (ok) + yield return method; + } + } + + IEnumerable GetFilteredNonMethods(Predicate filter) where TUnresolved : class, IUnresolvedMember where TResolved : class, IMember + { + var members = GetMemberList(); + for (int i = 0; i < members.unresolvedMembers.Length; i++) { + TUnresolved unresolved = members.unresolvedMembers[i] as TUnresolved; + if (unresolved != null && (filter == null || filter(unresolved))) { + yield return (TResolved)members[i]; + } + } + } + + public virtual IEnumerable GetMethods(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetFilteredMethods(Utils.ExtensionMethods.And(m => !m.IsConstructor, filter)); + } else { + return GetMembersHelper.GetMethods(this, filter, options); + } + } + + public virtual IEnumerable GetMethods(IList typeArguments, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + return GetMembersHelper.GetMethods(this, typeArguments, filter, options); + } + + public virtual IEnumerable GetConstructors(Predicate filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers) + { + if (ComHelper.IsComImport(this)) { + IType coClass = ComHelper.GetCoClass(this); + using (var busyLock = BusyManager.Enter(this)) { + if (busyLock.Success) { + return coClass.GetConstructors(filter, options) + .Select(m => new SpecializedMethod(m, m.Substitution) { DeclaringType = this }); + } + } + return EmptyList.Instance; + } + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetFilteredMethods(Utils.ExtensionMethods.And(m => m.IsConstructor && !m.IsStatic, filter)); + } else { + return GetMembersHelper.GetConstructors(this, filter, options); + } + } + + public virtual IEnumerable GetProperties(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetFilteredNonMethods(filter); + } else { + return GetMembersHelper.GetProperties(this, filter, options); + } + } + + public virtual IEnumerable GetFields(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetFilteredNonMethods(filter); + } else { + return GetMembersHelper.GetFields(this, filter, options); + } + } + + public virtual IEnumerable GetEvents(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetFilteredNonMethods(filter); + } else { + return GetMembersHelper.GetEvents(this, filter, options); + } + } + + public virtual IEnumerable GetMembers(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetFilteredMembers(filter); + } else { + return GetMembersHelper.GetMembers(this, filter, options); + } + } + + public virtual IEnumerable GetAccessors(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetFilteredAccessors(filter); + } else { + return GetMembersHelper.GetAccessors(this, filter, options); + } + } + + IEnumerable GetFilteredAccessors(Predicate filter) + { + var members = GetMemberList(); + for (int i = 0; i < members.unresolvedMembers.Length; i++) { + IUnresolvedMember unresolved = members.unresolvedMembers[i]; + var unresolvedProperty = unresolved as IUnresolvedProperty; + var unresolvedEvent = unresolved as IUnresolvedEvent; + if (unresolvedProperty != null) { + if (unresolvedProperty.CanGet && (filter == null || filter(unresolvedProperty.Getter))) + yield return ((IProperty)members[i]).Getter; + if (unresolvedProperty.CanSet && (filter == null || filter(unresolvedProperty.Setter))) + yield return ((IProperty)members[i]).Setter; + } else if (unresolvedEvent != null) { + if (unresolvedEvent.CanAdd && (filter == null || filter(unresolvedEvent.AddAccessor))) + yield return ((IEvent)members[i]).AddAccessor; + if (unresolvedEvent.CanRemove && (filter == null || filter(unresolvedEvent.RemoveAccessor))) + yield return ((IEvent)members[i]).RemoveAccessor; + if (unresolvedEvent.CanInvoke && (filter == null || filter(unresolvedEvent.InvokeAccessor))) + yield return ((IEvent)members[i]).InvokeAccessor; + } + } + } + #endregion + + #region GetInterfaceImplementation + public IMember GetInterfaceImplementation(IMember interfaceMember) + { + return GetInterfaceImplementation(new[] { interfaceMember })[0]; + } + + public IList GetInterfaceImplementation(IList interfaceMembers) + { + // TODO: review the subtle rules for interface reimplementation, + // write tests and fix this method. + // Also virtual/override is going to be tricky - + // I think we'll need to consider the 'virtual' method first for + // reimplemenatation purposes, but then actually return the 'override' + // (as that's the method that ends up getting called) + + interfaceMembers = interfaceMembers.ToList(); // avoid evaluating more than once + + var result = new IMember[interfaceMembers.Count]; + var signatureToIndexDict = new MultiDictionary(SignatureComparer.Ordinal); + for (int i = 0; i < interfaceMembers.Count; i++) { + signatureToIndexDict.Add(interfaceMembers[i], i); + } + foreach (var member in GetMembers(m => !m.IsExplicitInterfaceImplementation)) { + foreach (int interfaceMemberIndex in signatureToIndexDict[member]) { + result[interfaceMemberIndex] = member; + } + } + foreach (var explicitImpl in GetMembers(m => m.IsExplicitInterfaceImplementation)) { + foreach (var interfaceMember in explicitImpl.ImplementedInterfaceMembers) { + foreach (int potentialMatchingIndex in signatureToIndexDict[interfaceMember]) { + if (interfaceMember.Equals(interfaceMembers[potentialMatchingIndex])) { + result[potentialMatchingIndex] = explicitImpl; + } + } + } + } + return result; + } + #endregion + + public TypeParameterSubstitution GetSubstitution() + { + return TypeParameterSubstitution.Identity; + } + + public TypeParameterSubstitution GetSubstitution(IList methodTypeArguments) + { + return TypeParameterSubstitution.Identity; + } + + public bool Equals(IType other) + { + return this == other; + } + + public override string ToString() + { + return this.ReflectionName; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedTypeParameter.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedTypeParameter.cs new file mode 100644 index 000000000..ea0968ce1 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedTypeParameter.cs @@ -0,0 +1,257 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; +using System.Threading; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + public class DefaultTypeParameter : AbstractTypeParameter + { + readonly bool hasValueTypeConstraint; + readonly bool hasReferenceTypeConstraint; + readonly bool hasDefaultConstructorConstraint; + readonly IList constraints; + + public DefaultTypeParameter( + IEntity owner, + int index, string name = null, + VarianceModifier variance = VarianceModifier.Invariant, + IList attributes = null, + DomRegion region = default(DomRegion), + bool hasValueTypeConstraint = false, bool hasReferenceTypeConstraint = false, bool hasDefaultConstructorConstraint = false, + IList constraints = null) + : base(owner, index, name, variance, attributes, region) + { + this.hasValueTypeConstraint = hasValueTypeConstraint; + this.hasReferenceTypeConstraint = hasReferenceTypeConstraint; + this.hasDefaultConstructorConstraint = hasDefaultConstructorConstraint; + this.constraints = constraints ?? EmptyList.Instance; + } + + public DefaultTypeParameter( + ICompilation compilation, SymbolKind ownerType, + int index, string name = null, + VarianceModifier variance = VarianceModifier.Invariant, + IList attributes = null, + DomRegion region = default(DomRegion), + bool hasValueTypeConstraint = false, bool hasReferenceTypeConstraint = false, bool hasDefaultConstructorConstraint = false, + IList constraints = null) + : base(compilation, ownerType, index, name, variance, attributes, region) + { + this.hasValueTypeConstraint = hasValueTypeConstraint; + this.hasReferenceTypeConstraint = hasReferenceTypeConstraint; + this.hasDefaultConstructorConstraint = hasDefaultConstructorConstraint; + this.constraints = constraints ?? EmptyList.Instance; + } + + public override bool HasValueTypeConstraint { + get { return hasValueTypeConstraint; } + } + + public override bool HasReferenceTypeConstraint { + get { return hasReferenceTypeConstraint; } + } + + public override bool HasDefaultConstructorConstraint { + get { return hasDefaultConstructorConstraint; } + } + + public override IEnumerable DirectBaseTypes { + get { + bool hasNonInterfaceConstraint = false; + foreach (IType c in constraints) { + yield return c; + if (c.Kind != TypeKind.Interface) + hasNonInterfaceConstraint = true; + } + // Do not add the 'System.Object' constraint if there is another constraint with a base class. + if (this.HasValueTypeConstraint || !hasNonInterfaceConstraint) { + yield return this.Compilation.FindType(this.HasValueTypeConstraint ? KnownTypeCode.ValueType : KnownTypeCode.Object); + } + } + } + } + + /* + /// + /// Default implementation of . + /// + [Serializable] + public sealed class DefaultTypeParameter : AbstractTypeParameter + { + IList constraints; + + BitVector16 flags; + + const ushort FlagReferenceTypeConstraint = 0x0001; + const ushort FlagValueTypeConstraint = 0x0002; + const ushort FlagDefaultConstructorConstraint = 0x0004; + + protected override void FreezeInternal() + { + constraints = FreezeList(constraints); + base.FreezeInternal(); + } + + public DefaultTypeParameter(SymbolKind ownerType, int index, string name) + : base(ownerType, index, name) + { + } + + public IList Constraints { + get { + if (constraints == null) + constraints = new List(); + return constraints; + } + } + + public bool HasDefaultConstructorConstraint { + get { return flags[FlagDefaultConstructorConstraint]; } + set { + CheckBeforeMutation(); + flags[FlagDefaultConstructorConstraint] = value; + } + } + + public bool HasReferenceTypeConstraint { + get { return flags[FlagReferenceTypeConstraint]; } + set { + CheckBeforeMutation(); + flags[FlagReferenceTypeConstraint] = value; + } + } + + public bool HasValueTypeConstraint { + get { return flags[FlagValueTypeConstraint]; } + set { + CheckBeforeMutation(); + flags[FlagValueTypeConstraint] = value; + } + } + + public override bool? IsReferenceType(ITypeResolveContext context) + { + switch (flags.Data & (FlagReferenceTypeConstraint | FlagValueTypeConstraint)) { + case FlagReferenceTypeConstraint: + return true; + case FlagValueTypeConstraint: + return false; + } + + return base.IsReferenceTypeHelper(GetEffectiveBaseClass(context)); + } + + public override IType GetEffectiveBaseClass(ITypeResolveContext context) + { + // protect against cyclic type parameters + using (var busyLock = BusyManager.Enter(this)) { + if (!busyLock.Success) + return SpecialTypes.UnknownType; + + if (HasValueTypeConstraint) + return context.GetTypeDefinition("System", "ValueType", 0, StringComparer.Ordinal) ?? SpecialTypes.UnknownType; + + List classTypeConstraints = new List(); + foreach (ITypeReference constraintRef in this.Constraints) { + IType constraint = constraintRef.Resolve(context); + if (constraint.Kind == TypeKind.Class) { + classTypeConstraints.Add(constraint); + } else if (constraint.Kind == TypeKind.TypeParameter) { + IType baseClass = ((ITypeParameter)constraint).GetEffectiveBaseClass(context); + if (baseClass.Kind == TypeKind.Class) + classTypeConstraints.Add(baseClass); + } + } + if (classTypeConstraints.Count == 0) + return KnownTypeReference.Object.Resolve(context); + // Find the derived-most type in the resulting set: + IType result = classTypeConstraints[0]; + for (int i = 1; i < classTypeConstraints.Count; i++) { + if (classTypeConstraints[i].GetDefinition().IsDerivedFrom(result.GetDefinition(), context)) + result = classTypeConstraints[i]; + } + return result; + } + } + + public override IEnumerable GetEffectiveInterfaceSet(ITypeResolveContext context) + { + List result = new List(); + // protect against cyclic type parameters + using (var busyLock = BusyManager.Enter(this)) { + if (busyLock.Success) { + foreach (ITypeReference constraintRef in this.Constraints) { + IType constraint = constraintRef.Resolve(context); + if (constraint.Kind == TypeKind.Interface) { + result.Add(constraint); + } else if (constraint.Kind == TypeKind.TypeParameter) { + result.AddRange(((ITypeParameter)constraint).GetEffectiveInterfaceSet(context)); + } + } + } + } + return result.Distinct(); + } + + public override ITypeParameterConstraints GetConstraints(ITypeResolveContext context) + { + return new DefaultTypeParameterConstraints( + this.Constraints.Select(c => c.Resolve(context)), + this.HasDefaultConstructorConstraint, this.HasReferenceTypeConstraint, this.HasValueTypeConstraint); + } + + /* + * Interning for type parameters is disabled; we can't intern cyclic structures as might + * occur in the constraints, and incomplete interning is dangerous for type parameters + * as we use reference equality. + void ISupportsInterning.PrepareForInterning(IInterningProvider provider) + { + // protect against cyclic constraints + using (var busyLock = BusyManager.Enter(this)) { + if (busyLock.Success) { + constraints = provider.InternList(constraints); + base.PrepareForInterning(provider); + } + } + } + + int ISupportsInterning.GetHashCodeForInterning() + { + unchecked { + int hashCode = base.GetHashCodeForInterning(); + if (constraints != null) + hashCode += constraints.GetHashCode(); + hashCode += 771 * flags.Data; + return hashCode; + } + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + DefaultTypeParameter o = other as DefaultTypeParameter; + return base.EqualsForInterning(o) + && this.constraints == o.constraints + && this.flags == o.flags; + } + }*/ +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs new file mode 100644 index 000000000..de9834ccb --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs @@ -0,0 +1,575 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.Serialization; +using System.Threading; + +using ICSharpCode.NRefactory.Semantics; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Default implementation for . + /// + [Serializable] + public class DefaultUnresolvedAssembly : AbstractFreezable, IUnresolvedAssembly + { + string assemblyName; + string fullAssemblyName; + IList assemblyAttributes; + IList moduleAttributes; + Dictionary typeDefinitions = new Dictionary(TopLevelTypeNameComparer.Ordinal); + Dictionary typeForwarders = new Dictionary(TopLevelTypeNameComparer.Ordinal); + + protected override void FreezeInternal() + { + base.FreezeInternal(); + assemblyAttributes = FreezableHelper.FreezeListAndElements(assemblyAttributes); + moduleAttributes = FreezableHelper.FreezeListAndElements(moduleAttributes); + foreach (var type in typeDefinitions.Values) { + FreezableHelper.Freeze(type); + } + } + + /// + /// Creates a new unresolved assembly. + /// + /// Full assembly name + public DefaultUnresolvedAssembly(string assemblyName) + { + if (assemblyName == null) + throw new ArgumentNullException("assemblyName"); + this.fullAssemblyName = assemblyName; + int pos = assemblyName != null ? assemblyName.IndexOf(',') : -1; + this.assemblyName = pos < 0 ? assemblyName : assemblyName.Substring(0, pos); + this.assemblyAttributes = new List(); + this.moduleAttributes = new List(); + } + + /// + /// Gets/Sets the short assembly name. + /// + /// + /// This class handles the short and the full name independently; + /// if you change the short name, you should also change the full name. + /// + public string AssemblyName { + get { return assemblyName; } + set { + if (value == null) + throw new ArgumentNullException("value"); + FreezableHelper.ThrowIfFrozen(this); + assemblyName = value; + } + } + + /// + /// Gets/Sets the full assembly name. + /// + /// + /// This class handles the short and the full name independently; + /// if you change the full name, you should also change the short name. + /// + public string FullAssemblyName { + get { return fullAssemblyName; } + set { + if (value == null) + throw new ArgumentNullException("value"); + FreezableHelper.ThrowIfFrozen(this); + fullAssemblyName = value; + } + } + + string location; + public string Location { + get { + return location; + } + set { + FreezableHelper.ThrowIfFrozen(this); + location = value; + } + } + + public IList AssemblyAttributes { + get { return assemblyAttributes; } + } + + IEnumerable IUnresolvedAssembly.AssemblyAttributes { + get { return assemblyAttributes; } + } + + public IList ModuleAttributes { + get { return moduleAttributes; } + } + + IEnumerable IUnresolvedAssembly.ModuleAttributes { + get { return moduleAttributes; } + } + + public IEnumerable TopLevelTypeDefinitions { + get { return typeDefinitions.Values; } + } + + /// + /// Adds a new top-level type definition to this assembly. + /// + /// DefaultUnresolvedAssembly does not support partial classes. + /// Adding more than one part of a type will cause an ArgumentException. + public void AddTypeDefinition(IUnresolvedTypeDefinition typeDefinition) + { + if (typeDefinition == null) + throw new ArgumentNullException("typeDefinition"); + if (typeDefinition.DeclaringTypeDefinition != null) + throw new ArgumentException("Cannot add nested types."); + FreezableHelper.ThrowIfFrozen(this); + var key = new TopLevelTypeName(typeDefinition.Namespace, typeDefinition.Name, typeDefinition.TypeParameters.Count); + typeDefinitions.Add(key, typeDefinition); + } + + static readonly ITypeReference typeForwardedToAttributeTypeRef = typeof(System.Runtime.CompilerServices.TypeForwardedToAttribute).ToTypeReference(); + + /// + /// Adds a type forwarder. + /// This adds both an assembly attribute and an internal forwarder entry, which will be used + /// by the resolved assembly to provide the forwarded types. + /// + /// The name of the type. + /// The reference used to look up the type in the target assembly. + public void AddTypeForwarder(TopLevelTypeName typeName, ITypeReference referencedType) + { + if (referencedType == null) + throw new ArgumentNullException("referencedType"); + FreezableHelper.ThrowIfFrozen(this); + var attribute = new DefaultUnresolvedAttribute(typeForwardedToAttributeTypeRef, new[] { KnownTypeReference.Type }); + attribute.PositionalArguments.Add(new TypeOfConstantValue(referencedType)); + assemblyAttributes.Add(attribute); + + typeForwarders[typeName] = referencedType; + } + + [Serializable] + sealed class TypeOfConstantValue : IConstantValue + { + readonly ITypeReference typeRef; + + public TypeOfConstantValue(ITypeReference typeRef) + { + this.typeRef = typeRef; + } + + public ResolveResult Resolve(ITypeResolveContext context) + { + return new TypeOfResolveResult(context.Compilation.FindType(KnownTypeCode.Type), typeRef.Resolve(context)); + } + } + + public IUnresolvedTypeDefinition GetTypeDefinition(string ns, string name, int typeParameterCount) + { + var key = new TopLevelTypeName(ns ?? string.Empty, name, typeParameterCount); + IUnresolvedTypeDefinition td; + if (typeDefinitions.TryGetValue(key, out td)) + return td; + else + return null; + } + + public IAssembly Resolve(ITypeResolveContext context) + { + if (context == null) + throw new ArgumentNullException("context"); + Freeze(); + var cache = context.Compilation.CacheManager; + IAssembly asm = (IAssembly)cache.GetShared(this); + if (asm != null) { + return asm; + } else { + asm = new DefaultResolvedAssembly(context.Compilation, this); + return (IAssembly)cache.GetOrAddShared(this, asm); + } + } + + public override string ToString() + { + return "[" + GetType().Name + " " + assemblyName + "]"; + } + + //[NonSerialized] + //List> cachedTypeDictionariesPerNameComparer; + + Dictionary GetTypeDictionary(StringComparer nameComparer) + { + Debug.Assert(IsFrozen); + if (nameComparer == StringComparer.Ordinal) + return typeDefinitions; + else + throw new NotImplementedException(); + } + + #region UnresolvedNamespace + sealed class UnresolvedNamespace + { + internal readonly string FullName; + internal readonly string Name; + internal readonly List Children = new List(); + + public UnresolvedNamespace(string fullName, string name) + { + this.FullName = fullName; + this.Name = name; + } + } + + [NonSerialized] + List> unresolvedNamespacesPerNameComparer; + + UnresolvedNamespace GetUnresolvedRootNamespace(StringComparer nameComparer) + { + Debug.Assert(IsFrozen); + LazyInitializer.EnsureInitialized(ref unresolvedNamespacesPerNameComparer); + lock (unresolvedNamespacesPerNameComparer) { + foreach (var pair in unresolvedNamespacesPerNameComparer) { + if (pair.Key == nameComparer) + return pair.Value; + } + var root = new UnresolvedNamespace(string.Empty, string.Empty); + var dict = new Dictionary(nameComparer); + dict.Add(root.FullName, root); + foreach (var typeName in typeDefinitions.Keys) { + GetOrAddNamespace(dict, typeName.Namespace); + } + unresolvedNamespacesPerNameComparer.Add(new KeyValuePair(nameComparer, root)); + return root; + } + } + + static UnresolvedNamespace GetOrAddNamespace(Dictionary dict, string fullName) + { + UnresolvedNamespace ns; + if (dict.TryGetValue(fullName, out ns)) + return ns; + int pos = fullName.LastIndexOf('.'); + UnresolvedNamespace parent; + string name; + if (pos < 0) { + parent = dict[string.Empty]; // root + name = fullName; + } else { + parent = GetOrAddNamespace(dict, fullName.Substring(0, pos)); + name = fullName.Substring(pos + 1); + } + ns = new UnresolvedNamespace(fullName, name); + parent.Children.Add(ns); + dict.Add(fullName, ns); + return ns; + } + #endregion + + sealed class DefaultResolvedAssembly : IAssembly + { + readonly DefaultUnresolvedAssembly unresolvedAssembly; + readonly ICompilation compilation; + readonly ITypeResolveContext context; + readonly Dictionary unresolvedTypeDict; + readonly ConcurrentDictionary typeDict = new ConcurrentDictionary(); + readonly INamespace rootNamespace; + + public DefaultResolvedAssembly(ICompilation compilation, DefaultUnresolvedAssembly unresolved) + { + this.compilation = compilation; + this.unresolvedAssembly = unresolved; + this.unresolvedTypeDict = unresolved.GetTypeDictionary(compilation.NameComparer); + this.rootNamespace = new NS(this, unresolved.GetUnresolvedRootNamespace(compilation.NameComparer), null); + this.context = new SimpleTypeResolveContext(this); + this.AssemblyAttributes = unresolved.AssemblyAttributes.CreateResolvedAttributes(context); + this.ModuleAttributes = unresolved.ModuleAttributes.CreateResolvedAttributes(context); + } + + public IUnresolvedAssembly UnresolvedAssembly { + get { return unresolvedAssembly; } + } + + public bool IsMainAssembly { + get { return this.Compilation.MainAssembly == this; } + } + + public string AssemblyName { + get { return unresolvedAssembly.AssemblyName; } + } + + public string FullAssemblyName { + get { return unresolvedAssembly.FullAssemblyName; } + } + + public IList AssemblyAttributes { get; private set; } + public IList ModuleAttributes { get; private set; } + + public INamespace RootNamespace { + get { return rootNamespace; } + } + + public ICompilation Compilation { + get { return compilation; } + } + + public bool InternalsVisibleTo(IAssembly assembly) + { + if (this == assembly) + return true; + foreach (string shortName in GetInternalsVisibleTo()) { + if (assembly.AssemblyName == shortName) + return true; + } + return false; + } + + volatile string[] internalsVisibleTo; + + string[] GetInternalsVisibleTo() + { + var result = this.internalsVisibleTo; + if (result != null) { + return result; + } else { + using (var busyLock = BusyManager.Enter(this)) { + Debug.Assert(busyLock.Success); + if (!busyLock.Success) { + return new string[0]; + } + internalsVisibleTo = ( + from attr in this.AssemblyAttributes + where attr.AttributeType.Name == "InternalsVisibleToAttribute" + && attr.AttributeType.Namespace == "System.Runtime.CompilerServices" + && attr.PositionalArguments.Count == 1 + select GetShortName(attr.PositionalArguments.Single().ConstantValue as string) + ).ToArray(); + } + return internalsVisibleTo; + } + } + + static string GetShortName(string fullAssemblyName) + { + if (fullAssemblyName == null) + return null; + int pos = fullAssemblyName.IndexOf(','); + if (pos < 0) + return fullAssemblyName; + else + return fullAssemblyName.Substring(0, pos); + } + + public ITypeDefinition GetTypeDefinition(TopLevelTypeName topLevelTypeName) + { + IUnresolvedTypeDefinition td; + ITypeReference typeRef; + if (unresolvedAssembly.typeDefinitions.TryGetValue(topLevelTypeName, out td)) + return GetTypeDefinition(td); + if (unresolvedAssembly.typeForwarders.TryGetValue(topLevelTypeName, out typeRef)) { + // Protect against cyclic type forwarders: + using (var busyLock = BusyManager.Enter(typeRef)) { + if (busyLock.Success) + return typeRef.Resolve(compilation.TypeResolveContext).GetDefinition(); + } + } + return null; + } + + ITypeDefinition GetTypeDefinition(IUnresolvedTypeDefinition unresolved) + { + return typeDict.GetOrAdd(unresolved, t => CreateTypeDefinition(t)); + } + + ITypeDefinition CreateTypeDefinition(IUnresolvedTypeDefinition unresolved) + { + if (unresolved.DeclaringTypeDefinition != null) { + ITypeDefinition declaringType = GetTypeDefinition(unresolved.DeclaringTypeDefinition); + return new DefaultResolvedTypeDefinition(context.WithCurrentTypeDefinition(declaringType), unresolved); + } else if (unresolved.Name == "Void" && unresolved.Namespace == "System" && unresolved.TypeParameters.Count == 0) { + return new VoidTypeDefinition(context, unresolved); + } else { + return new DefaultResolvedTypeDefinition(context, unresolved); + } + } + + public IEnumerable TopLevelTypeDefinitions { + get { + return unresolvedAssembly.TopLevelTypeDefinitions.Select(t => GetTypeDefinition(t)); + } + } + + public override string ToString() + { + return "[DefaultResolvedAssembly " + AssemblyName + "]"; + } + + sealed class NS : INamespace + { + readonly DefaultResolvedAssembly assembly; + readonly UnresolvedNamespace ns; + readonly INamespace parentNamespace; + readonly IList childNamespaces; + IEnumerable types; + + public NS(DefaultResolvedAssembly assembly, UnresolvedNamespace ns, INamespace parentNamespace) + { + this.assembly = assembly; + this.ns = ns; + this.parentNamespace = parentNamespace; + this.childNamespaces = new ProjectedList( + this, ns.Children, (self, c) => new NS(self.assembly, c, self)); + } + + string INamespace.ExternAlias { + get { return null; } + } + + string INamespace.FullName { + get { return ns.FullName; } + } + + SymbolKind ISymbol.SymbolKind { + get { return SymbolKind.Namespace; } + } + + public string Name { + get { return ns.Name; } + } + + INamespace INamespace.ParentNamespace { + get { return parentNamespace; } + } + + IEnumerable INamespace.ContributingAssemblies { + get { return new [] { assembly }; } + } + + IEnumerable INamespace.ChildNamespaces { + get { return childNamespaces; } + } + + INamespace INamespace.GetChildNamespace(string name) + { + var nameComparer = assembly.compilation.NameComparer; + for (int i = 0; i < childNamespaces.Count; i++) { + if (nameComparer.Equals(name, ns.Children[i].Name)) + return childNamespaces[i]; + } + return null; + } + + ICompilation ICompilationProvider.Compilation { + get { return assembly.compilation; } + } + + IEnumerable INamespace.Types { + get { + var result = LazyInit.VolatileRead(ref this.types); + if (result != null) { + return result; + } else { + var hashSet = new HashSet(); + foreach (IUnresolvedTypeDefinition typeDef in assembly.UnresolvedAssembly.TopLevelTypeDefinitions) { + if (typeDef.Namespace == ns.FullName) + hashSet.Add(assembly.GetTypeDefinition(typeDef)); + } + return LazyInit.GetOrSet(ref this.types, hashSet.ToArray()); + } + } + } + + ITypeDefinition INamespace.GetTypeDefinition(string name, int typeParameterCount) + { + var key = new TopLevelTypeName(ns.FullName, name, typeParameterCount); + IUnresolvedTypeDefinition unresolvedTypeDef; + if (assembly.unresolvedTypeDict.TryGetValue(key, out unresolvedTypeDef)) + return assembly.GetTypeDefinition(unresolvedTypeDef); + else + return null; + } + + public ISymbolReference ToReference() + { + return new NamespaceReference(new DefaultAssemblyReference(assembly.AssemblyName), ns.FullName); + } + } + } + } + + public sealed class NamespaceReference : ISymbolReference + { + IAssemblyReference assemblyReference; + string fullName; + + public NamespaceReference(IAssemblyReference assemblyReference, string fullName) + { + if (assemblyReference == null) + throw new ArgumentNullException("assemblyReference"); + this.assemblyReference = assemblyReference; + this.fullName = fullName; + } + + public ISymbol Resolve(ITypeResolveContext context) + { + IAssembly assembly = assemblyReference.Resolve(context); + INamespace parent = assembly.RootNamespace; + + string[] parts = fullName.Split('.'); + + int i = 0; + while (i < parts.Length && parent != null) { + parent = parent.GetChildNamespace(parts[i]); + i++; + } + + return parent; + } + } + + public sealed class MergedNamespaceReference : ISymbolReference + { + string externAlias; + string fullName; + + public MergedNamespaceReference(string externAlias, string fullName) + { + this.externAlias = externAlias; + this.fullName = fullName; + } + + public ISymbol Resolve(ITypeResolveContext context) + { + string[] parts = fullName.Split('.'); + INamespace parent = context.Compilation.GetNamespaceForExternAlias(externAlias); + + int i = 0; + while (i < parts.Length && parent != null) { + parent = parent.GetChildNamespace(parts[i]); + i++; + } + + return parent; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedAttribute.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedAttribute.cs new file mode 100644 index 000000000..ac30211de --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedAttribute.cs @@ -0,0 +1,283 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Semantics; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Default implementation of . + /// + [Serializable] + public sealed class DefaultUnresolvedAttribute : AbstractFreezable, IUnresolvedAttribute, IFreezable, ISupportsInterning + { + ITypeReference attributeType; + DomRegion region; + IList constructorParameterTypes; + IList positionalArguments; + IList> namedArguments; + + public DefaultUnresolvedAttribute(ITypeReference attributeType) + { + if (attributeType == null) + throw new ArgumentNullException("attributeType"); + this.attributeType = attributeType; + } + + public DefaultUnresolvedAttribute(ITypeReference attributeType, IEnumerable constructorParameterTypes) + { + if (attributeType == null) + throw new ArgumentNullException("attributeType"); + this.attributeType = attributeType; + this.ConstructorParameterTypes.AddRange(constructorParameterTypes); + } + + protected override void FreezeInternal() + { + base.FreezeInternal(); + constructorParameterTypes = FreezableHelper.FreezeList(constructorParameterTypes); + positionalArguments = FreezableHelper.FreezeListAndElements(positionalArguments); + namedArguments = FreezableHelper.FreezeList(namedArguments); + foreach (var pair in namedArguments) { + FreezableHelper.Freeze(pair.Key); + FreezableHelper.Freeze(pair.Value); + } + } + + public ITypeReference AttributeType { + get { return attributeType; } + } + + public DomRegion Region { + get { return region; } + set { + FreezableHelper.ThrowIfFrozen(this); + region = value; + } + } + + public IList ConstructorParameterTypes { + get { + if (constructorParameterTypes == null) + constructorParameterTypes = new List(); + return constructorParameterTypes; + } + } + + public IList PositionalArguments { + get { + if (positionalArguments == null) + positionalArguments = new List(); + return positionalArguments; + } + } + + public IList> NamedArguments { + get { + if (namedArguments == null) + namedArguments = new List>(); + return namedArguments; + } + } + + public void AddNamedFieldArgument(string fieldName, IConstantValue value) + { + this.NamedArguments.Add(new KeyValuePair( + new DefaultMemberReference(SymbolKind.Field, attributeType, fieldName), + value + )); + } + + public void AddNamedPropertyArgument(string propertyName, IConstantValue value) + { + this.NamedArguments.Add(new KeyValuePair( + new DefaultMemberReference(SymbolKind.Property, attributeType, propertyName), + value + )); + } + + public IAttribute CreateResolvedAttribute(ITypeResolveContext context) + { + return new DefaultResolvedAttribute(this, context); + } + + int ISupportsInterning.GetHashCodeForInterning() + { + int hash = attributeType.GetHashCode() ^ constructorParameterTypes.GetHashCode(); + unchecked { + if (constructorParameterTypes != null) { + foreach (var type in constructorParameterTypes) { + hash *= 27; + hash += type.GetHashCode(); + } + } + if (positionalArguments != null) { + foreach (var arg in positionalArguments) { + hash *= 31; + hash += arg.GetHashCode(); + } + } + if (namedArguments != null) { + foreach (var pair in namedArguments) { + hash *= 71; + hash += pair.Key.GetHashCode() + pair.Value.GetHashCode() * 73; + } + } + } + return hash; + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + DefaultUnresolvedAttribute o = other as DefaultUnresolvedAttribute; + return o != null && attributeType == o.attributeType + && ListEquals(constructorParameterTypes, o.constructorParameterTypes) + && ListEquals(positionalArguments, o.positionalArguments) + && ListEquals(namedArguments ?? EmptyList>.Instance, + o.namedArguments ?? EmptyList>.Instance); + } + + static bool ListEquals(IList list1, IList list2) where T : class + { + if (list1 == null) + list1 = EmptyList.Instance; + if (list2 == null) + list2 = EmptyList.Instance; + if (list1 == list2) + return true; + if (list1.Count != list2.Count) + return false; + for (int i = 0; i < list1.Count; i++) { + if (list1[i] != list2[i]) + return false; + } + return true; + } + + static bool ListEquals(IList> list1, IList> list2) + { + if (list1 == list2) + return true; + if (list1.Count != list2.Count) + return false; + for (int i = 0; i < list1.Count; i++) { + var a = list1[i]; + var b = list2[i]; + if (!(a.Key == b.Key && a.Value == b.Value)) + return false; + } + return true; + } + + sealed class DefaultResolvedAttribute : IAttribute, ICompilationProvider + { + readonly DefaultUnresolvedAttribute unresolved; + readonly ITypeResolveContext context; + readonly IType attributeType; + readonly IList positionalArguments; + + // cannot use ProjectedList because KeyValuePair is value type + IList> namedArguments; + + IMethod constructor; + volatile bool constructorResolved; + + public DefaultResolvedAttribute(DefaultUnresolvedAttribute unresolved, ITypeResolveContext context) + { + this.unresolved = unresolved; + this.context = context; + + this.attributeType = unresolved.AttributeType.Resolve(context); + this.positionalArguments = unresolved.PositionalArguments.Resolve(context); + } + + public IType AttributeType { + get { return attributeType; } + } + + public DomRegion Region { + get { return unresolved.Region; } + } + + public IMethod Constructor { + get { + if (!constructorResolved) { + constructor = ResolveConstructor(); + constructorResolved = true; + } + return constructor; + } + } + + IMethod ResolveConstructor() + { + var parameterTypes = unresolved.ConstructorParameterTypes.Resolve(context); + foreach (var ctor in attributeType.GetConstructors(m => m.Parameters.Count == parameterTypes.Count)) { + bool ok = true; + for (int i = 0; i < parameterTypes.Count; i++) { + if (!ctor.Parameters[i].Type.Equals(parameterTypes[i])) { + ok = false; + break; + } + } + if (ok) + return ctor; + } + return null; + } + + public IList PositionalArguments { + get { return positionalArguments; } + } + + public IList> NamedArguments { + get { + var namedArgs = LazyInit.VolatileRead(ref this.namedArguments); + if (namedArgs != null) { + return namedArgs; + } else { + namedArgs = new List>(); + foreach (var pair in unresolved.NamedArguments) { + IMember member = pair.Key.Resolve(context); + if (member != null) { + ResolveResult val = pair.Value.Resolve(context); + namedArgs.Add(new KeyValuePair(member, val)); + } + } + return LazyInit.GetOrSet(ref this.namedArguments, namedArgs); + } + } + } + + public ICompilation Compilation { + get { return context.Compilation; } + } + + public override string ToString() + { + if (positionalArguments.Count == 0) + return "[" + attributeType.ToString() + "]"; + else + return "[" + attributeType.ToString() + "(...)]"; + } + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedEvent.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedEvent.cs new file mode 100644 index 000000000..f9abd1a6a --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedEvent.cs @@ -0,0 +1,99 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Default implementation of . + /// + [Serializable] + public class DefaultUnresolvedEvent : AbstractUnresolvedMember, IUnresolvedEvent + { + IUnresolvedMethod addAccessor, removeAccessor, invokeAccessor; + + protected override void FreezeInternal() + { + base.FreezeInternal(); + FreezableHelper.Freeze(addAccessor); + FreezableHelper.Freeze(removeAccessor); + FreezableHelper.Freeze(invokeAccessor); + } + + public DefaultUnresolvedEvent() + { + this.SymbolKind = SymbolKind.Event; + } + + public DefaultUnresolvedEvent(IUnresolvedTypeDefinition declaringType, string name) + { + this.SymbolKind = SymbolKind.Event; + this.DeclaringTypeDefinition = declaringType; + this.Name = name; + if (declaringType != null) + this.UnresolvedFile = declaringType.UnresolvedFile; + } + + public bool CanAdd { + get { return addAccessor != null; } + } + + public bool CanRemove { + get { return removeAccessor != null; } + } + + public bool CanInvoke { + get { return invokeAccessor != null; } + } + + public IUnresolvedMethod AddAccessor { + get { return addAccessor; } + set { + ThrowIfFrozen(); + addAccessor = value; + } + } + + public IUnresolvedMethod RemoveAccessor { + get { return removeAccessor; } + set { + ThrowIfFrozen(); + removeAccessor = value; + } + } + + public IUnresolvedMethod InvokeAccessor { + get { return invokeAccessor; } + set { + ThrowIfFrozen(); + invokeAccessor = value; + } + } + + public override IMember CreateResolved(ITypeResolveContext context) + { + return new DefaultResolvedEvent(this, context); + } + + IEvent IUnresolvedEvent.Resolve(ITypeResolveContext context) + { + return (IEvent)Resolve(context); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedField.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedField.cs new file mode 100644 index 000000000..6b578e6f5 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedField.cs @@ -0,0 +1,97 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Default implementation of . + /// + [Serializable] + public class DefaultUnresolvedField : AbstractUnresolvedMember, IUnresolvedField + { + IConstantValue constantValue; + + protected override void FreezeInternal() + { + FreezableHelper.Freeze(constantValue); + base.FreezeInternal(); + } + + public DefaultUnresolvedField() + { + this.SymbolKind = SymbolKind.Field; + } + + public DefaultUnresolvedField(IUnresolvedTypeDefinition declaringType, string name) + { + this.SymbolKind = SymbolKind.Field; + this.DeclaringTypeDefinition = declaringType; + this.Name = name; + if (declaringType != null) + this.UnresolvedFile = declaringType.UnresolvedFile; + } + + public bool IsConst { + get { return constantValue != null && !IsFixed; } + } + + public bool IsReadOnly { + get { return flags[FlagFieldIsReadOnly]; } + set { + ThrowIfFrozen(); + flags[FlagFieldIsReadOnly] = value; + } + } + + public bool IsVolatile { + get { return flags[FlagFieldIsVolatile]; } + set { + ThrowIfFrozen(); + flags[FlagFieldIsVolatile] = value; + } + } + + public bool IsFixed { + get { return flags[FlagFieldIsFixedSize]; } + set { + ThrowIfFrozen(); + flags[FlagFieldIsFixedSize] = value; + } + } + + public IConstantValue ConstantValue { + get { return constantValue; } + set { + ThrowIfFrozen(); + constantValue = value; + } + } + + public override IMember CreateResolved(ITypeResolveContext context) + { + return new DefaultResolvedField(this, context); + } + + IField IUnresolvedField.Resolve(ITypeResolveContext context) + { + return (IField)Resolve(context); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedMethod.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedMethod.cs new file mode 100644 index 000000000..3e8c61c64 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedMethod.cs @@ -0,0 +1,287 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; +using System.Text; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Default implementation of interface. + /// + [Serializable] + public class DefaultUnresolvedMethod : AbstractUnresolvedMember, IUnresolvedMethod + { + IList returnTypeAttributes; + IList typeParameters; + IList parameters; + IUnresolvedMember accessorOwner; + + protected override void FreezeInternal() + { + returnTypeAttributes = FreezableHelper.FreezeListAndElements(returnTypeAttributes); + typeParameters = FreezableHelper.FreezeListAndElements(typeParameters); + parameters = FreezableHelper.FreezeListAndElements(parameters); + base.FreezeInternal(); + } + + public override object Clone() + { + var copy = (DefaultUnresolvedMethod)base.Clone(); + if (returnTypeAttributes != null) + copy.returnTypeAttributes = new List(returnTypeAttributes); + if (typeParameters != null) + copy.typeParameters = new List(typeParameters); + if (parameters != null) + copy.parameters = new List(parameters); + return copy; + } + + public override void ApplyInterningProvider(InterningProvider provider) + { + base.ApplyInterningProvider(provider); + if (provider != null) { + returnTypeAttributes = provider.InternList(returnTypeAttributes); + typeParameters = provider.InternList(typeParameters); + parameters = provider.InternList(parameters); + } + } + + public DefaultUnresolvedMethod() + { + this.SymbolKind = SymbolKind.Method; + } + + public DefaultUnresolvedMethod(IUnresolvedTypeDefinition declaringType, string name) + { + this.SymbolKind = SymbolKind.Method; + this.DeclaringTypeDefinition = declaringType; + this.Name = name; + if (declaringType != null) + this.UnresolvedFile = declaringType.UnresolvedFile; + } + + public IList ReturnTypeAttributes { + get { + if (returnTypeAttributes == null) + returnTypeAttributes = new List(); + return returnTypeAttributes; + } + } + + public IList TypeParameters { + get { + if (typeParameters == null) + typeParameters = new List(); + return typeParameters; + } + } + + public bool IsExtensionMethod { + get { return flags[FlagExtensionMethod]; } + set { + ThrowIfFrozen(); + flags[FlagExtensionMethod] = value; + } + } + + public bool IsConstructor { + get { return this.SymbolKind == SymbolKind.Constructor; } + } + + public bool IsDestructor { + get { return this.SymbolKind == SymbolKind.Destructor; } + } + + public bool IsOperator { + get { return this.SymbolKind == SymbolKind.Operator; } + } + + public bool IsPartial { + get { return flags[FlagPartialMethod]; } + set { + ThrowIfFrozen(); + flags[FlagPartialMethod] = value; + } + } + + public bool IsAsync { + get { return flags[FlagAsyncMethod]; } + set { + ThrowIfFrozen(); + flags[FlagAsyncMethod] = value; + } + } + + public bool HasBody { + get { return flags[FlagHasBody]; } + set { + ThrowIfFrozen(); + flags[FlagHasBody] = value; + } + } + + [Obsolete] + public bool IsPartialMethodDeclaration { + get { return IsPartial && !HasBody; } + set { + if (value) { + IsPartial = true; + HasBody = false; + } else if (!value && IsPartial && !HasBody) { + IsPartial = false; + } + } + } + + [Obsolete] + public bool IsPartialMethodImplementation { + get { return IsPartial && HasBody; } + set { + if (value) { + IsPartial = true; + HasBody = true; + } else if (!value && IsPartial && HasBody) { + IsPartial = false; + } + } + } + + public IList Parameters { + get { + if (parameters == null) + parameters = new List(); + return parameters; + } + } + + public IUnresolvedMember AccessorOwner { + get { return accessorOwner; } + set { + ThrowIfFrozen(); + accessorOwner = value; + } + } + + public override string ToString() + { + StringBuilder b = new StringBuilder("["); + b.Append(SymbolKind.ToString()); + b.Append(' '); + if (DeclaringTypeDefinition != null) { + b.Append(DeclaringTypeDefinition.Name); + b.Append('.'); + } + b.Append(Name); + b.Append('('); + b.Append(string.Join(", ", this.Parameters)); + b.Append("):"); + b.Append(ReturnType.ToString()); + b.Append(']'); + return b.ToString(); + } + + public override IMember CreateResolved(ITypeResolveContext context) + { + return new DefaultResolvedMethod(this, context); + } + + public override IMember Resolve(ITypeResolveContext context) + { + if (accessorOwner != null) { + var owner = accessorOwner.Resolve(context); + if (owner != null) { + IProperty p = owner as IProperty; + if (p != null) { + if (p.CanGet && p.Getter.Name == this.Name) + return p.Getter; + if (p.CanSet && p.Setter.Name == this.Name) + return p.Setter; + } + IEvent e = owner as IEvent; + if (e != null) { + if (e.CanAdd && e.AddAccessor.Name == this.Name) + return e.AddAccessor; + if (e.CanRemove && e.RemoveAccessor.Name == this.Name) + return e.RemoveAccessor; + if (e.CanInvoke && e.InvokeAccessor.Name == this.Name) + return e.InvokeAccessor; + } + } + return null; + } + + ITypeReference interfaceTypeReference = null; + if (this.IsExplicitInterfaceImplementation && this.ExplicitInterfaceImplementations.Count == 1) + interfaceTypeReference = this.ExplicitInterfaceImplementations[0].DeclaringTypeReference; + return Resolve(ExtendContextForType(context, this.DeclaringTypeDefinition), + this.SymbolKind, this.Name, interfaceTypeReference, + this.TypeParameters.Select(tp => tp.Name).ToList(), + this.Parameters.Select(p => p.Type).ToList()); + } + + IMethod IUnresolvedMethod.Resolve(ITypeResolveContext context) + { + return (IMethod)Resolve(context); + } + + public static DefaultUnresolvedMethod CreateDefaultConstructor(IUnresolvedTypeDefinition typeDefinition) + { + if (typeDefinition == null) + throw new ArgumentNullException("typeDefinition"); + DomRegion region = typeDefinition.Region; + region = new DomRegion(region.FileName, region.BeginLine, region.BeginColumn); // remove endline/endcolumn + return new DefaultUnresolvedMethod(typeDefinition, ".ctor") { + SymbolKind = SymbolKind.Constructor, + Accessibility = typeDefinition.IsAbstract ? Accessibility.Protected : Accessibility.Public, + IsSynthetic = true, + HasBody = true, + Region = region, + BodyRegion = region, + ReturnType = KnownTypeReference.Void + }; + } + + static readonly IUnresolvedMethod dummyConstructor = CreateDummyConstructor(); + + /// + /// Returns a dummy constructor instance: + /// + /// + /// A public instance constructor with IsSynthetic=true and no declaring type. + /// + public static IUnresolvedMethod DummyConstructor { + get { return dummyConstructor; } + } + + static IUnresolvedMethod CreateDummyConstructor() + { + var m = new DefaultUnresolvedMethod { + SymbolKind = SymbolKind.Constructor, + Name = ".ctor", + Accessibility = Accessibility.Public, + IsSynthetic = true, + ReturnType = KnownTypeReference.Void + }; + m.Freeze(); + return m; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedParameter.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedParameter.cs new file mode 100644 index 000000000..d57197fa8 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedParameter.cs @@ -0,0 +1,275 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; +using System.Text; +using ICSharpCode.NRefactory.Semantics; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Default implementation for IUnresolvedParameter. + /// + [Serializable] + public sealed class DefaultUnresolvedParameter : IUnresolvedParameter, IFreezable, ISupportsInterning + { + string name = string.Empty; + ITypeReference type = SpecialType.UnknownType; + IList attributes; + IConstantValue defaultValue; + DomRegion region; + byte flags; + + public DefaultUnresolvedParameter() + { + } + + public DefaultUnresolvedParameter(ITypeReference type, string name) + { + if (type == null) + throw new ArgumentNullException("type"); + if (name == null) + throw new ArgumentNullException("name"); + this.type = type; + this.name = name; + } + + void FreezeInternal() + { + attributes = FreezableHelper.FreezeListAndElements(attributes); + FreezableHelper.Freeze(defaultValue); + } + + public string Name { + get { return name; } + set { + if (value == null) + throw new ArgumentNullException("value"); + FreezableHelper.ThrowIfFrozen(this); + name = value; + } + } + + public ITypeReference Type { + get { return type; } + set { + if (value == null) + throw new ArgumentNullException("value"); + FreezableHelper.ThrowIfFrozen(this); + type = value; + } + } + + public IList Attributes { + get { + if (attributes == null) + attributes = new List(); + return attributes; + } + } + + public IConstantValue DefaultValue { + get { return defaultValue; } + set { + FreezableHelper.ThrowIfFrozen(this); + defaultValue = value; + } + } + + public DomRegion Region { + get { return region; } + set { + FreezableHelper.ThrowIfFrozen(this); + region = value; + } + } + + bool HasFlag(byte flag) + { + return (this.flags & flag) != 0; + } + void SetFlag(byte flag, bool value) + { + FreezableHelper.ThrowIfFrozen(this); + if (value) + this.flags |= flag; + else + this.flags &= unchecked((byte)~flag); + } + + public bool IsFrozen { + get { return HasFlag(1); } + } + + public void Freeze() + { + if (!this.IsFrozen) { + FreezeInternal(); + this.flags |= 1; + } + } + + public bool IsRef { + get { return HasFlag(2); } + set { SetFlag(2, value); } + } + + public bool IsOut { + get { return HasFlag(4); } + set { SetFlag(4, value); } + } + + public bool IsParams { + get { return HasFlag(8); } + set { SetFlag(8, value); } + } + + public bool IsOptional { + get { return this.DefaultValue != null; } + } + + int ISupportsInterning.GetHashCodeForInterning() + { + unchecked { + int hashCode = 1919191 ^ (flags & ~1); + hashCode *= 31; + hashCode += type.GetHashCode(); + hashCode *= 31; + hashCode += name.GetHashCode(); + if (attributes != null) { + foreach (var attr in attributes) + hashCode ^= attr.GetHashCode (); + } + if (defaultValue != null) + hashCode ^= defaultValue.GetHashCode (); + return hashCode; + } + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + // compare everything except for the IsFrozen flag + DefaultUnresolvedParameter p = other as DefaultUnresolvedParameter; + return p != null && type == p.type && name == p.name && + defaultValue == p.defaultValue && region == p.region && (flags & ~1) == (p.flags & ~1) && ListEquals(attributes, p.attributes); + } + + static bool ListEquals(IList list1, IList list2) + { + return (list1 ?? EmptyList.Instance).SequenceEqual(list2 ?? EmptyList.Instance); + } + + public override string ToString() + { + StringBuilder b = new StringBuilder(); + if (IsRef) + b.Append("ref "); + if (IsOut) + b.Append("out "); + if (IsParams) + b.Append("params "); + b.Append(name); + b.Append(':'); + b.Append(type.ToString()); + if (defaultValue != null) { + b.Append(" = "); + b.Append(defaultValue.ToString()); + } + return b.ToString(); + } + + static bool IsOptionalAttribute (IType attributeType) + { + return attributeType.Name == "OptionalAttribute" && attributeType.Namespace == "System.Runtime.InteropServices"; + } + + public IParameter CreateResolvedParameter(ITypeResolveContext context) + { + Freeze(); + if (defaultValue != null) { + return new ResolvedParameterWithDefaultValue(defaultValue, context) { + Type = type.Resolve(context), + Name = name, + Region = region, + Attributes = attributes.CreateResolvedAttributes(context), + IsRef = this.IsRef, + IsOut = this.IsOut, + IsParams = this.IsParams + }; + } else { + var owner = context.CurrentMember as IParameterizedMember; + var resolvedAttributes = attributes.CreateResolvedAttributes (context); + bool isOptional = resolvedAttributes != null && resolvedAttributes.Any (a => IsOptionalAttribute (a.AttributeType)); + return new DefaultParameter (type.Resolve (context), name, owner, region, + resolvedAttributes, IsRef, IsOut, IsParams, isOptional); + } + } + + sealed class ResolvedParameterWithDefaultValue : IParameter + { + readonly IConstantValue defaultValue; + readonly ITypeResolveContext context; + + public ResolvedParameterWithDefaultValue(IConstantValue defaultValue, ITypeResolveContext context) + { + this.defaultValue = defaultValue; + this.context = context; + } + + SymbolKind ISymbol.SymbolKind { get { return SymbolKind.Parameter; } } + public IParameterizedMember Owner { get { return context.CurrentMember as IParameterizedMember; } } + public IType Type { get; internal set; } + public string Name { get; internal set; } + public DomRegion Region { get; internal set; } + public IList Attributes { get; internal set; } + public bool IsRef { get; internal set; } + public bool IsOut { get; internal set; } + public bool IsParams { get; internal set; } + public bool IsOptional { get { return true; } } + bool IVariable.IsConst { get { return false; } } + + ResolveResult resolvedDefaultValue; + + public object ConstantValue { + get { + ResolveResult rr = LazyInit.VolatileRead(ref this.resolvedDefaultValue); + if (rr == null) { + rr = defaultValue.Resolve(context); + LazyInit.GetOrSet(ref this.resolvedDefaultValue, rr); + } + return rr.ConstantValue; + } + } + + public override string ToString() + { + return DefaultParameter.ToString(this); + } + + public ISymbolReference ToReference() + { + if (Owner == null) + return new ParameterReference(Type.ToTypeReference(), Name, Region, IsRef, IsOut, IsParams, true, ConstantValue); + return new OwnedParameterReference(Owner.ToReference(), Owner.Parameters.IndexOf(this)); + } + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedProperty.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedProperty.cs new file mode 100644 index 000000000..d8113f36e --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedProperty.cs @@ -0,0 +1,126 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Default implementation of . + /// + [Serializable] + public class DefaultUnresolvedProperty : AbstractUnresolvedMember, IUnresolvedProperty + { + IUnresolvedMethod getter, setter; + IList parameters; + + protected override void FreezeInternal() + { + parameters = FreezableHelper.FreezeListAndElements(parameters); + FreezableHelper.Freeze(getter); + FreezableHelper.Freeze(setter); + base.FreezeInternal(); + } + + public override object Clone() + { + var copy = (DefaultUnresolvedProperty)base.Clone(); + if (parameters != null) + copy.parameters = new List(parameters); + return copy; + } + + public override void ApplyInterningProvider(InterningProvider provider) + { + base.ApplyInterningProvider(provider); + parameters = provider.InternList(parameters); + } + + public DefaultUnresolvedProperty() + { + this.SymbolKind = SymbolKind.Property; + } + + public DefaultUnresolvedProperty(IUnresolvedTypeDefinition declaringType, string name) + { + this.SymbolKind = SymbolKind.Property; + this.DeclaringTypeDefinition = declaringType; + this.Name = name; + if (declaringType != null) + this.UnresolvedFile = declaringType.UnresolvedFile; + } + + public bool IsIndexer { + get { return this.SymbolKind == SymbolKind.Indexer; } + } + + public IList Parameters { + get { + if (parameters == null) + parameters = new List(); + return parameters; + } + } + + public bool CanGet { + get { return getter != null; } + } + + public bool CanSet { + get { return setter != null; } + } + + public IUnresolvedMethod Getter { + get { return getter; } + set { + ThrowIfFrozen(); + getter = value; + } + } + + public IUnresolvedMethod Setter { + get { return setter; } + set { + ThrowIfFrozen(); + setter = value; + } + } + + public override IMember CreateResolved(ITypeResolveContext context) + { + return new DefaultResolvedProperty(this, context); + } + + public override IMember Resolve(ITypeResolveContext context) + { + ITypeReference interfaceTypeReference = null; + if (this.IsExplicitInterfaceImplementation && this.ExplicitInterfaceImplementations.Count == 1) + interfaceTypeReference = this.ExplicitInterfaceImplementations[0].DeclaringTypeReference; + return Resolve(ExtendContextForType(context, this.DeclaringTypeDefinition), + this.SymbolKind, this.Name, interfaceTypeReference, + parameterTypeReferences: this.Parameters.Select(p => p.Type).ToList()); + } + + IProperty IUnresolvedProperty.Resolve(ITypeResolveContext context) + { + return (IProperty)Resolve(context); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedTypeDefinition.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedTypeDefinition.cs new file mode 100644 index 000000000..cc35adf94 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedTypeDefinition.cs @@ -0,0 +1,240 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Globalization; +using System.Linq; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Represents an unresolved type definition. + /// + [Serializable] + public class DefaultUnresolvedTypeDefinition : AbstractUnresolvedEntity, IUnresolvedTypeDefinition + { + TypeKind kind = TypeKind.Class; + string namespaceName; + IList baseTypes; + IList typeParameters; + IList nestedTypes; + IList members; + + public DefaultUnresolvedTypeDefinition() + { + this.SymbolKind = SymbolKind.TypeDefinition; + } + + public DefaultUnresolvedTypeDefinition(string fullName) + { + string namespaceName; + string name; + int idx = fullName.LastIndexOf ('.'); + if (idx > 0) { + namespaceName = fullName.Substring (0, idx); + name = fullName.Substring (idx + 1); + } else { + namespaceName = ""; + name = fullName; + } + + this.SymbolKind = SymbolKind.TypeDefinition; + this.namespaceName = namespaceName; + this.Name = name; + } + + public DefaultUnresolvedTypeDefinition(string namespaceName, string name) + { + this.SymbolKind = SymbolKind.TypeDefinition; + this.namespaceName = namespaceName; + this.Name = name; + } + + public DefaultUnresolvedTypeDefinition(IUnresolvedTypeDefinition declaringTypeDefinition, string name) + { + this.SymbolKind = SymbolKind.TypeDefinition; + this.DeclaringTypeDefinition = declaringTypeDefinition; + this.namespaceName = declaringTypeDefinition.Namespace; + this.Name = name; + this.UnresolvedFile = declaringTypeDefinition.UnresolvedFile; + } + + protected override void FreezeInternal() + { + base.FreezeInternal(); + baseTypes = FreezableHelper.FreezeList(baseTypes); + typeParameters = FreezableHelper.FreezeListAndElements(typeParameters); + nestedTypes = FreezableHelper.FreezeListAndElements(nestedTypes); + members = FreezableHelper.FreezeListAndElements(members); + } + + public override object Clone() + { + var copy = (DefaultUnresolvedTypeDefinition)base.Clone(); + if (baseTypes != null) + copy.baseTypes = new List(baseTypes); + if (typeParameters != null) + copy.typeParameters = new List(typeParameters); + if (nestedTypes != null) + copy.nestedTypes = new List(nestedTypes); + if (members != null) + copy.members = new List(members); + return copy; + } + + public TypeKind Kind { + get { return kind; } + set { + ThrowIfFrozen(); + kind = value; + } + } + + public bool AddDefaultConstructorIfRequired { + get { return flags[FlagAddDefaultConstructorIfRequired]; } + set { + ThrowIfFrozen(); + flags[FlagAddDefaultConstructorIfRequired] = value; + } + } + + public bool? HasExtensionMethods { + get { + if (flags[FlagHasExtensionMethods]) + return true; + else if (flags[FlagHasNoExtensionMethods]) + return false; + else + return null; + } + set { + ThrowIfFrozen(); + flags[FlagHasExtensionMethods] = (value == true); + flags[FlagHasNoExtensionMethods] = (value == false); + } + } + + public bool IsPartial { + get { return flags[FlagPartialTypeDefinition]; } + set { + ThrowIfFrozen(); + flags[FlagPartialTypeDefinition] = value; + } + } + + public override string Namespace { + get { return namespaceName; } + set { + if (value == null) + throw new ArgumentNullException("value"); + ThrowIfFrozen(); + namespaceName = value; + } + } + + public override string ReflectionName { + get { + return this.FullTypeName.ReflectionName; + } + } + + public FullTypeName FullTypeName { + get { + IUnresolvedTypeDefinition declaringTypeDef = this.DeclaringTypeDefinition; + if (declaringTypeDef != null) { + return declaringTypeDef.FullTypeName.NestedType(this.Name, this.TypeParameters.Count - declaringTypeDef.TypeParameters.Count); + } else { + return new TopLevelTypeName(namespaceName, this.Name, this.TypeParameters.Count); + } + } + } + + public IList BaseTypes { + get { + if (baseTypes == null) + baseTypes = new List(); + return baseTypes; + } + } + + public IList TypeParameters { + get { + if (typeParameters == null) + typeParameters = new List(); + return typeParameters; + } + } + + public IList NestedTypes { + get { + if (nestedTypes == null) + nestedTypes = new List(); + return nestedTypes; + } + } + + public IList Members { + get { + if (members == null) + members = new List(); + return members; + } + } + + public IEnumerable Methods { + get { + return Members.OfType (); + } + } + + public IEnumerable Properties { + get { + return Members.OfType (); + } + } + + public IEnumerable Fields { + get { + return Members.OfType (); + } + } + + public IEnumerable Events { + get { + return Members.OfType (); + } + } + + + public IType Resolve(ITypeResolveContext context) + { + if (context == null) + throw new ArgumentNullException("context"); + if (context.CurrentAssembly == null) + throw new ArgumentException("An ITypeDefinition cannot be resolved in a context without a current assembly."); + return context.CurrentAssembly.GetTypeDefinition(this.FullTypeName) + ?? (IType)new UnknownType(this.Namespace, this.Name, this.TypeParameters.Count); + } + + public virtual ITypeResolveContext CreateResolveContext(ITypeResolveContext parentContext) + { + return parentContext; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedTypeParameter.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedTypeParameter.cs new file mode 100644 index 000000000..492d3e222 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedTypeParameter.cs @@ -0,0 +1,194 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Globalization; + +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Default implementation of . + /// + [Serializable] + public class DefaultUnresolvedTypeParameter : IUnresolvedTypeParameter, IFreezable + { + readonly int index; + IList attributes; + IList constraints; + string name; + DomRegion region; + + SymbolKind ownerType; + VarianceModifier variance; + BitVector16 flags; + const ushort FlagFrozen = 0x0001; + const ushort FlagReferenceTypeConstraint = 0x0002; + const ushort FlagValueTypeConstraint = 0x0004; + const ushort FlagDefaultConstructorConstraint = 0x0008; + + public void Freeze() + { + if (!flags[FlagFrozen]) { + FreezeInternal(); + flags[FlagFrozen] = true; + } + } + + protected virtual void FreezeInternal() + { + attributes = FreezableHelper.FreezeListAndElements(attributes); + constraints = FreezableHelper.FreezeList(constraints); + } + + public DefaultUnresolvedTypeParameter(SymbolKind ownerType, int index, string name = null) + { + this.ownerType = ownerType; + this.index = index; + this.name = name ?? ((ownerType == SymbolKind.Method ? "!!" : "!") + index.ToString(CultureInfo.InvariantCulture)); + } + + public SymbolKind OwnerType { + get { return ownerType; } + } + + public int Index { + get { return index; } + } + + public bool IsFrozen { + get { return flags[FlagFrozen]; } + } + + public string Name { + get { return name; } + set { + FreezableHelper.ThrowIfFrozen(this); + name = value; + } + } + + string INamedElement.FullName { + get { return name; } + } + + string INamedElement.Namespace { + get { return string.Empty; } + } + + string INamedElement.ReflectionName { + get { + if (ownerType == SymbolKind.Method) + return "``" + index.ToString(CultureInfo.InvariantCulture); + else + return "`" + index.ToString(CultureInfo.InvariantCulture); + } + } + + public IList Attributes { + get { + if (attributes == null) + attributes = new List(); + return attributes; + } + } + + public IList Constraints { + get { + if (constraints == null) + constraints = new List(); + return constraints; + } + } + + public VarianceModifier Variance { + get { return variance; } + set { + FreezableHelper.ThrowIfFrozen(this); + variance = value; + } + } + + public DomRegion Region { + get { return region; } + set { + FreezableHelper.ThrowIfFrozen(this); + region = value; + } + } + + public bool HasDefaultConstructorConstraint { + get { return flags[FlagDefaultConstructorConstraint]; } + set { + FreezableHelper.ThrowIfFrozen(this); + flags[FlagDefaultConstructorConstraint] = value; + } + } + + public bool HasReferenceTypeConstraint { + get { return flags[FlagReferenceTypeConstraint]; } + set { + FreezableHelper.ThrowIfFrozen(this); + flags[FlagReferenceTypeConstraint] = value; + } + } + + public bool HasValueTypeConstraint { + get { return flags[FlagValueTypeConstraint]; } + set { + FreezableHelper.ThrowIfFrozen(this); + flags[FlagValueTypeConstraint] = value; + } + } + + /// + /// Uses the specified interning provider to intern + /// strings and lists in this entity. + /// This method does not test arbitrary objects to see if they implement ISupportsInterning; + /// instead we assume that those are interned immediately when they are created (before they are added to this entity). + /// + public virtual void ApplyInterningProvider(InterningProvider provider) + { + if (provider == null) + throw new ArgumentNullException("provider"); + FreezableHelper.ThrowIfFrozen(this); + name = provider.Intern(name); + attributes = provider.InternList(attributes); + constraints = provider.InternList(constraints); + } + + public virtual ITypeParameter CreateResolvedTypeParameter(ITypeResolveContext context) + { + IEntity owner = null; + if (this.OwnerType == SymbolKind.Method) { + owner = context.CurrentMember as IMethod; + } else if (this.OwnerType == SymbolKind.TypeDefinition) { + owner = context.CurrentTypeDefinition; + } + if (owner == null) + throw new InvalidOperationException("Could not determine the type parameter's owner."); + return new DefaultTypeParameter( + owner, index, name, variance, + this.Attributes.CreateResolvedAttributes(context), this.Region, + this.HasValueTypeConstraint, this.HasReferenceTypeConstraint, this.HasDefaultConstructorConstraint, this.Constraints.Resolve(context) + ); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultVariable.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultVariable.cs new file mode 100644 index 000000000..0ce0be0e0 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultVariable.cs @@ -0,0 +1,109 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Default implementation of . + /// + public sealed class DefaultVariable : IVariable + { + readonly string name; + readonly DomRegion region; + readonly IType type; + readonly object constantValue; + readonly bool isConst; + + public DefaultVariable(IType type, string name) + { + if (type == null) + throw new ArgumentNullException("type"); + if (name == null) + throw new ArgumentNullException("name"); + this.type = type; + this.name = name; + } + + public DefaultVariable(IType type, string name, DomRegion region = default(DomRegion), + bool isConst = false, object constantValue = null) + : this(type, name) + { + this.region = region; + this.isConst = isConst; + this.constantValue = constantValue; + } + + public string Name { + get { return name; } + } + + public DomRegion Region { + get { return region; } + } + + public IType Type { + get { return type; } + } + + public bool IsConst { + get { return isConst; } + } + + public object ConstantValue { + get { return constantValue; } + } + + public SymbolKind SymbolKind { + get { return SymbolKind.Variable; } + } + + public ISymbolReference ToReference() + { + return new VariableReference(type.ToTypeReference(), name, region, isConst, constantValue); + } + } + + public sealed class VariableReference : ISymbolReference + { + ITypeReference variableTypeReference; + string name; + DomRegion region; + bool isConst; + object constantValue; + + public VariableReference(ITypeReference variableTypeReference, string name, DomRegion region, bool isConst, object constantValue) + { + if (variableTypeReference == null) + throw new ArgumentNullException("variableTypeReference"); + if (name == null) + throw new ArgumentNullException("name"); + this.variableTypeReference = variableTypeReference; + this.name = name; + this.region = region; + this.isConst = isConst; + this.constantValue = constantValue; + } + + public ISymbol Resolve(ITypeResolveContext context) + { + return new DefaultVariable(variableTypeReference.Resolve(context), name, region, isConst, constantValue); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DummyTypeParameter.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DummyTypeParameter.cs new file mode 100644 index 000000000..6530da822 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DummyTypeParameter.cs @@ -0,0 +1,217 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Threading; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + public sealed class DummyTypeParameter : AbstractType, ITypeParameter + { + static ITypeParameter[] methodTypeParameters = { new DummyTypeParameter(SymbolKind.Method, 0) }; + static ITypeParameter[] classTypeParameters = { new DummyTypeParameter(SymbolKind.TypeDefinition, 0) }; + + public static ITypeParameter GetMethodTypeParameter(int index) + { + return GetTypeParameter(ref methodTypeParameters, SymbolKind.Method, index); + } + + public static ITypeParameter GetClassTypeParameter(int index) + { + return GetTypeParameter(ref classTypeParameters, SymbolKind.TypeDefinition, index); + } + + static ITypeParameter GetTypeParameter(ref ITypeParameter[] typeParameters, SymbolKind symbolKind, int index) + { + ITypeParameter[] tps = typeParameters; + while (index >= tps.Length) { + // We don't have a normal type parameter for this index, so we need to extend our array. + // Because the array can be used concurrently from multiple threads, we have to use + // Interlocked.CompareExchange. + ITypeParameter[] newTps = new ITypeParameter[index + 1]; + tps.CopyTo(newTps, 0); + for (int i = tps.Length; i < newTps.Length; i++) { + newTps[i] = new DummyTypeParameter(symbolKind, i); + } + ITypeParameter[] oldTps = Interlocked.CompareExchange(ref typeParameters, newTps, tps); + if (oldTps == tps) { + // exchange successful + tps = newTps; + } else { + // exchange not successful + tps = oldTps; + } + } + return tps[index]; + } + + sealed class NormalizeMethodTypeParametersVisitor : TypeVisitor + { + public override IType VisitTypeParameter(ITypeParameter type) + { + if (type.OwnerType == SymbolKind.Method) { + return DummyTypeParameter.GetMethodTypeParameter(type.Index); + } else { + return base.VisitTypeParameter(type); + } + } + } + sealed class NormalizeClassTypeParametersVisitor : TypeVisitor + { + public override IType VisitTypeParameter(ITypeParameter type) + { + if (type.OwnerType == SymbolKind.TypeDefinition) { + return DummyTypeParameter.GetClassTypeParameter(type.Index); + } else { + return base.VisitTypeParameter(type); + } + } + } + + static readonly NormalizeMethodTypeParametersVisitor normalizeMethodTypeParameters = new NormalizeMethodTypeParametersVisitor(); + static readonly NormalizeClassTypeParametersVisitor normalizeClassTypeParameters = new NormalizeClassTypeParametersVisitor(); + + /// + /// Replaces all occurrences of method type parameters in the given type + /// by normalized type parameters. This allows comparing parameter types from different + /// generic methods. + /// + public static IType NormalizeMethodTypeParameters(IType type) + { + return type.AcceptVisitor(normalizeMethodTypeParameters); + } + + /// + /// Replaces all occurrences of class type parameters in the given type + /// by normalized type parameters. This allows comparing parameter types from different + /// generic methods. + /// + public static IType NormalizeClassTypeParameters(IType type) + { + return type.AcceptVisitor(normalizeClassTypeParameters); + } + + /// + /// Replaces all occurrences of class and method type parameters in the given type + /// by normalized type parameters. This allows comparing parameter types from different + /// generic methods. + /// + public static IType NormalizeAllTypeParameters(IType type) + { + return type.AcceptVisitor(normalizeClassTypeParameters).AcceptVisitor(normalizeMethodTypeParameters); + } + + readonly SymbolKind ownerType; + readonly int index; + + private DummyTypeParameter(SymbolKind ownerType, int index) + { + this.ownerType = ownerType; + this.index = index; + } + + SymbolKind ISymbol.SymbolKind { + get { return SymbolKind.TypeParameter; } + } + + public override string Name { + get { + return (ownerType == SymbolKind.Method ? "!!" : "!") + index; + } + } + + public override string ReflectionName { + get { + return (ownerType == SymbolKind.Method ? "``" : "`") + index; + } + } + + public override string ToString() + { + return ReflectionName + " (dummy)"; + } + + public override bool? IsReferenceType { + get { return null; } + } + + public override TypeKind Kind { + get { return TypeKind.TypeParameter; } + } + + public override ITypeReference ToTypeReference() + { + return TypeParameterReference.Create(ownerType, index); + } + + public override IType AcceptVisitor(TypeVisitor visitor) + { + return visitor.VisitTypeParameter(this); + } + + public int Index { + get { return index; } + } + + IList ITypeParameter.Attributes { + get { return EmptyList.Instance; } + } + + SymbolKind ITypeParameter.OwnerType { + get { return ownerType; } + } + + VarianceModifier ITypeParameter.Variance { + get { return VarianceModifier.Invariant; } + } + + DomRegion ITypeParameter.Region { + get { return DomRegion.Empty; } + } + + IEntity ITypeParameter.Owner { + get { return null; } + } + + IType ITypeParameter.EffectiveBaseClass { + get { return SpecialType.UnknownType; } + } + + ICollection ITypeParameter.EffectiveInterfaceSet { + get { return EmptyList.Instance; } + } + + bool ITypeParameter.HasDefaultConstructorConstraint { + get { return false; } + } + + bool ITypeParameter.HasReferenceTypeConstraint { + get { return false; } + } + + bool ITypeParameter.HasValueTypeConstraint { + get { return false; } + } + + public ISymbolReference ToReference() + { + return new TypeParameterReference(ownerType, index); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/ExplicitInterfaceImplementationMemberReference.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/ExplicitInterfaceImplementationMemberReference.cs new file mode 100644 index 000000000..abe280028 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/ExplicitInterfaceImplementationMemberReference.cs @@ -0,0 +1,80 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// References a member that is an explicit interface implementation. + /// + /// + /// Resolving an ExplicitInterfaceImplementationMemberReference requires a context + /// that provides enough information for resolving the declaring type reference + /// and the interface member reference. + /// Note that the interface member reference is resolved in 'context.WithCurrentTypeDefinition(declaringType.GetDefinition())' + /// - this is done to ensure that open generics in the interface member reference resolve to the type parameters of the + /// declaring type. + /// + [Serializable] + public sealed class ExplicitInterfaceImplementationMemberReference : IMemberReference + { + ITypeReference typeReference; + IMemberReference interfaceMemberReference; + + public ExplicitInterfaceImplementationMemberReference(ITypeReference typeReference, IMemberReference interfaceMemberReference) + { + if (typeReference == null) + throw new ArgumentNullException("typeReference"); + if (interfaceMemberReference == null) + throw new ArgumentNullException("interfaceMemberReference"); + this.typeReference = typeReference; + this.interfaceMemberReference = interfaceMemberReference; + } + + public ITypeReference DeclaringTypeReference { + get { return typeReference; } + } + + public IMember Resolve(ITypeResolveContext context) + { + IType declaringType = typeReference.Resolve(context); + IMember interfaceMember = interfaceMemberReference.Resolve(context.WithCurrentTypeDefinition(declaringType.GetDefinition())); + if (interfaceMember == null) + return null; + IEnumerable members; + if (interfaceMember.SymbolKind == SymbolKind.Accessor) { + members = declaringType.GetAccessors( + m => m.IsExplicitInterfaceImplementation, + GetMemberOptions.IgnoreInheritedMembers); + } else { + members = declaringType.GetMembers( + m => m.SymbolKind == interfaceMember.SymbolKind && m.IsExplicitInterfaceImplementation, + GetMemberOptions.IgnoreInheritedMembers); + } + return members.FirstOrDefault(m => m.ImplementedInterfaceMembers.Count == 1 && interfaceMember.Equals(m.ImplementedInterfaceMembers[0])); + } + + ISymbol ISymbolReference.Resolve(ITypeResolveContext context) + { + return Resolve(context); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/FullNameAndTypeParameterCount.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/FullNameAndTypeParameterCount.cs new file mode 100644 index 000000000..302e896b9 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/FullNameAndTypeParameterCount.cs @@ -0,0 +1,28 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + [Obsolete("This struct was renamed to 'TopLevelTypeName'.", true)] + public struct FullNameAndTypeParameterCount + { + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/GetClassTypeReference.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/GetClassTypeReference.cs new file mode 100644 index 000000000..e465f1aee --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/GetClassTypeReference.cs @@ -0,0 +1,158 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Linq; +using System.Threading; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Type Reference used when the fully qualified type name is known. + /// + [Serializable] + public sealed class GetClassTypeReference : ITypeReference, ISymbolReference, ISupportsInterning + { + readonly IAssemblyReference assembly; + readonly FullTypeName fullTypeName; + + /// + /// Creates a new GetClassTypeReference that searches a type definition. + /// + /// The full name of the type. + /// A reference to the assembly containing this type. + /// If this parameter is null, the GetClassTypeReference will search in all + /// assemblies belonging to the compilation. + /// + public GetClassTypeReference(FullTypeName fullTypeName, IAssemblyReference assembly = null) + { + this.fullTypeName = fullTypeName; + this.assembly = assembly; + } + + /// + /// Creates a new GetClassTypeReference that searches a top-level type in all assemblies. + /// + /// The namespace name containing the type, e.g. "System.Collections.Generic". + /// The name of the type, e.g. "List". + /// The number of type parameters, (e.g. 1 for List<T>). + public GetClassTypeReference(string namespaceName, string name, int typeParameterCount = 0) + { + this.fullTypeName = new TopLevelTypeName(namespaceName, name, typeParameterCount); + } + + /// + /// Creates a new GetClassTypeReference that searches a top-level type in the specified assembly. + /// + /// A reference to the assembly containing this type. + /// If this parameter is null, the GetClassTypeReference will search in all assemblies belonging to the ICompilation. + /// The namespace name containing the type, e.g. "System.Collections.Generic". + /// The name of the type, e.g. "List". + /// The number of type parameters, (e.g. 1 for List<T>). + public GetClassTypeReference(IAssemblyReference assembly, string namespaceName, string name, int typeParameterCount = 0) + { + this.assembly = assembly; + this.fullTypeName = new TopLevelTypeName(namespaceName, name, typeParameterCount); + } + + /// + /// Gets the assembly reference. + /// This property returns null if the GetClassTypeReference is searching in all assemblies + /// of the compilation. + /// + public IAssemblyReference Assembly { get { return assembly; } } + + /// + /// Gets the full name of the type this reference is searching for. + /// + public FullTypeName FullTypeName { get { return fullTypeName; } } + + [Obsolete("Use the FullTypeName property instead. GetClassTypeReference now supports nested types, where the Namespace/Name/TPC tripel isn't sufficient for identifying the type.")] + public string Namespace { get { return fullTypeName.TopLevelTypeName.Namespace; } } + [Obsolete("Use the FullTypeName property instead. GetClassTypeReference now supports nested types, where the Namespace/Name/TPC tripel isn't sufficient for identifying the type.")] + public string Name { get { return fullTypeName.Name; } } + [Obsolete("Use the FullTypeName property instead. GetClassTypeReference now supports nested types, where the Namespace/Name/TPC tripel isn't sufficient for identifying the type.")] + public int TypeParameterCount { get { return fullTypeName.TypeParameterCount; } } + + IType ResolveInAllAssemblies(ITypeResolveContext context) + { + var compilation = context.Compilation; + foreach (var asm in compilation.Assemblies) { + IType type = asm.GetTypeDefinition(fullTypeName); + if (type != null) + return type; + } + return null; + } + + public IType Resolve(ITypeResolveContext context) + { + if (context == null) + throw new ArgumentNullException("context"); + + IType type = null; + if (assembly == null) { + // No assembly specified: look in all assemblies, but prefer the current assembly + if (context.CurrentAssembly != null) { + type = context.CurrentAssembly.GetTypeDefinition(fullTypeName); + } + if (type == null) { + type = ResolveInAllAssemblies(context); + } + } else { + // Assembly specified: only look in the specified assembly. + // But if that's not loaded in the compilation, allow fall back to other assemblies. + // (the non-loaded assembly might be a facade containing type forwarders - + // for example, when referencing a portable library from a non-portable project) + IAssembly asm = assembly.Resolve(context); + if (asm != null) { + type = asm.GetTypeDefinition(fullTypeName); + } else { + type = ResolveInAllAssemblies(context); + } + } + return type ?? new UnknownType(fullTypeName); + } + + ISymbol ISymbolReference.Resolve(ITypeResolveContext context) + { + var type = Resolve(context); + if (type is ITypeDefinition) + return (ISymbol)type; + return null; + } + + public override string ToString() + { + return fullTypeName.ToString() + (assembly != null ? ", " + assembly.ToString() : null); + } + + int ISupportsInterning.GetHashCodeForInterning() + { + unchecked { + return 33 * assembly.GetHashCode() + fullTypeName.GetHashCode(); + } + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + GetClassTypeReference o = other as GetClassTypeReference; + return o != null && assembly == o.assembly && fullTypeName == o.fullTypeName; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/GetMembersHelper.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/GetMembersHelper.cs new file mode 100644 index 000000000..881c56e7c --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/GetMembersHelper.cs @@ -0,0 +1,296 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Provides helper methods for implementing GetMembers() on IType-implementations. + /// Note: GetMembersHelper will recursively call back into IType.GetMembers(), but only with + /// both GetMemberOptions.IgnoreInheritedMembers and GetMemberOptions.ReturnMemberDefinitions set, + /// and only the 'simple' overloads (not taking type arguments). + /// + /// Ensure that your IType implementation does not use the GetMembersHelper if both flags are set, + /// otherwise you'll get a StackOverflowException! + /// + static class GetMembersHelper + { + #region GetNestedTypes + public static IEnumerable GetNestedTypes(IType type, Predicate filter, GetMemberOptions options) + { + return GetNestedTypes(type, null, filter, options); + } + + public static IEnumerable GetNestedTypes(IType type, IList nestedTypeArguments, Predicate filter, GetMemberOptions options) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetNestedTypesImpl(type, nestedTypeArguments, filter, options); + } else { + return type.GetNonInterfaceBaseTypes().SelectMany(t => GetNestedTypesImpl(t, nestedTypeArguments, filter, options)); + } + } + + static IEnumerable GetNestedTypesImpl(IType outerType, IList nestedTypeArguments, Predicate filter, GetMemberOptions options) + { + ITypeDefinition outerTypeDef = outerType.GetDefinition(); + if (outerTypeDef == null) + yield break; + + int outerTypeParameterCount = outerTypeDef.TypeParameterCount; + ParameterizedType pt = outerType as ParameterizedType; + foreach (ITypeDefinition nestedType in outerTypeDef.NestedTypes) { + int totalTypeParameterCount = nestedType.TypeParameterCount; + if (nestedTypeArguments != null) { + if (totalTypeParameterCount - outerTypeParameterCount != nestedTypeArguments.Count) + continue; + } + if (!(filter == null || filter(nestedType))) + continue; + + if (totalTypeParameterCount == 0 || (options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { + yield return nestedType; + } else { + // We need to parameterize the nested type + IType[] newTypeArguments = new IType[totalTypeParameterCount]; + for (int i = 0; i < outerTypeParameterCount; i++) { + newTypeArguments[i] = pt != null ? pt.GetTypeArgument(i) : outerTypeDef.TypeParameters[i]; + } + for (int i = outerTypeParameterCount; i < totalTypeParameterCount; i++) { + if (nestedTypeArguments != null) + newTypeArguments[i] = nestedTypeArguments[i - outerTypeParameterCount]; + else + newTypeArguments[i] = SpecialType.UnboundTypeArgument; + } + yield return new ParameterizedType(nestedType, newTypeArguments); + } + } + } + #endregion + + #region GetMethods + public static IEnumerable GetMethods(IType type, Predicate filter, GetMemberOptions options) + { + return GetMethods(type, null, filter, options); + } + + public static IEnumerable GetMethods(IType type, IList typeArguments, Predicate filter, GetMemberOptions options) + { + if (typeArguments != null && typeArguments.Count > 0) { + filter = FilterTypeParameterCount(typeArguments.Count).And(filter); + } + + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetMethodsImpl(type, typeArguments, filter, options); + } else { + return type.GetNonInterfaceBaseTypes().SelectMany(t => GetMethodsImpl(t, typeArguments, filter, options)); + } + } + + static Predicate FilterTypeParameterCount(int expectedTypeParameterCount) + { + return m => m.TypeParameters.Count == expectedTypeParameterCount; + } + + const GetMemberOptions declaredMembers = GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions; + + static IEnumerable GetMethodsImpl(IType baseType, IList methodTypeArguments, Predicate filter, GetMemberOptions options) + { + IEnumerable declaredMethods = baseType.GetMethods(filter, options | declaredMembers); + + ParameterizedType pt = baseType as ParameterizedType; + if ((options & GetMemberOptions.ReturnMemberDefinitions) == 0 + && (pt != null || (methodTypeArguments != null && methodTypeArguments.Count > 0))) + { + TypeParameterSubstitution substitution = null; + foreach (IMethod m in declaredMethods) { + if (methodTypeArguments != null && methodTypeArguments.Count > 0) { + if (m.TypeParameters.Count != methodTypeArguments.Count) + continue; + } + if (substitution == null) { + if (pt != null) + substitution = pt.GetSubstitution(methodTypeArguments); + else + substitution = new TypeParameterSubstitution(null, methodTypeArguments); + } + yield return new SpecializedMethod(m, substitution); + } + } else { + foreach (IMethod m in declaredMethods) { + yield return m; + } + } + } + #endregion + + #region GetAccessors + public static IEnumerable GetAccessors(IType type, Predicate filter, GetMemberOptions options) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetAccessorsImpl(type, filter, options); + } else { + return type.GetNonInterfaceBaseTypes().SelectMany(t => GetAccessorsImpl(t, filter, options)); + } + } + + static IEnumerable GetAccessorsImpl(IType baseType, Predicate filter, GetMemberOptions options) + { + return GetConstructorsOrAccessorsImpl(baseType, baseType.GetAccessors(filter, options | declaredMembers), filter, options); + } + #endregion + + #region GetConstructors + public static IEnumerable GetConstructors(IType type, Predicate filter, GetMemberOptions options) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetConstructorsImpl(type, filter, options); + } else { + return type.GetNonInterfaceBaseTypes().SelectMany(t => GetConstructorsImpl(t, filter, options)); + } + } + + static IEnumerable GetConstructorsImpl(IType baseType, Predicate filter, GetMemberOptions options) + { + return GetConstructorsOrAccessorsImpl(baseType, baseType.GetConstructors(filter, options | declaredMembers), filter, options); + } + + static IEnumerable GetConstructorsOrAccessorsImpl(IType baseType, IEnumerable declaredMembers, Predicate filter, GetMemberOptions options) + { + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { + return declaredMembers; + } + + ParameterizedType pt = baseType as ParameterizedType; + if (pt != null) { + var substitution = pt.GetSubstitution(); + return declaredMembers.Select(m => new SpecializedMethod(m, substitution) { DeclaringType = pt }); + } else { + return declaredMembers; + } + } + #endregion + + #region GetProperties + public static IEnumerable GetProperties(IType type, Predicate filter, GetMemberOptions options) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetPropertiesImpl(type, filter, options); + } else { + return type.GetNonInterfaceBaseTypes().SelectMany(t => GetPropertiesImpl(t, filter, options)); + } + } + + static IEnumerable GetPropertiesImpl(IType baseType, Predicate filter, GetMemberOptions options) + { + IEnumerable declaredProperties = baseType.GetProperties(filter, options | declaredMembers); + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { + return declaredProperties; + } + + ParameterizedType pt = baseType as ParameterizedType; + if (pt != null) { + var substitution = pt.GetSubstitution(); + return declaredProperties.Select(m => new SpecializedProperty(m, substitution) { DeclaringType = pt }); + } else { + return declaredProperties; + } + } + #endregion + + #region GetFields + public static IEnumerable GetFields(IType type, Predicate filter, GetMemberOptions options) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetFieldsImpl(type, filter, options); + } else { + return type.GetNonInterfaceBaseTypes().SelectMany(t => GetFieldsImpl(t, filter, options)); + } + } + + static IEnumerable GetFieldsImpl(IType baseType, Predicate filter, GetMemberOptions options) + { + IEnumerable declaredFields = baseType.GetFields(filter, options | declaredMembers); + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { + return declaredFields; + } + + ParameterizedType pt = baseType as ParameterizedType; + if (pt != null) { + var substitution = pt.GetSubstitution(); + return declaredFields.Select(m => new SpecializedField(m, substitution) { DeclaringType = pt }); + } else { + return declaredFields; + } + } + #endregion + + #region GetEvents + public static IEnumerable GetEvents(IType type, Predicate filter, GetMemberOptions options) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetEventsImpl(type, filter, options); + } else { + return type.GetNonInterfaceBaseTypes().SelectMany(t => GetEventsImpl(t, filter, options)); + } + } + + static IEnumerable GetEventsImpl(IType baseType, Predicate filter, GetMemberOptions options) + { + IEnumerable declaredEvents = baseType.GetEvents(filter, options | declaredMembers); + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { + return declaredEvents; + } + + ParameterizedType pt = baseType as ParameterizedType; + if (pt != null) { + var substitution = pt.GetSubstitution(); + return declaredEvents.Select(m => new SpecializedEvent(m, substitution) { DeclaringType = pt }); + } else { + return declaredEvents; + } + } + #endregion + + #region GetMembers + public static IEnumerable GetMembers(IType type, Predicate filter, GetMemberOptions options) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetMembersImpl(type, filter, options); + } else { + return type.GetNonInterfaceBaseTypes().SelectMany(t => GetMembersImpl(t, filter, options)); + } + } + + static IEnumerable GetMembersImpl(IType baseType, Predicate filter, GetMemberOptions options) + { + foreach (var m in GetMethodsImpl(baseType, null, filter, options)) + yield return m; + foreach (var m in GetPropertiesImpl(baseType, filter, options)) + yield return m; + foreach (var m in GetFieldsImpl(baseType, filter, options)) + yield return m; + foreach (var m in GetEventsImpl(baseType, filter, options)) + yield return m; + } + #endregion + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownTypeCache.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownTypeCache.cs new file mode 100644 index 000000000..9e984618a --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownTypeCache.cs @@ -0,0 +1,60 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Cache for KnownTypeReferences. + /// + sealed class KnownTypeCache + { + readonly ICompilation compilation; + readonly IType[] knownTypes = new IType[KnownTypeReference.KnownTypeCodeCount]; + + public KnownTypeCache(ICompilation compilation) + { + this.compilation = compilation; + } + + public IType FindType(KnownTypeCode typeCode) + { + IType type = LazyInit.VolatileRead(ref knownTypes[(int)typeCode]); + if (type != null) { + return type; + } + return LazyInit.GetOrSet(ref knownTypes[(int)typeCode], SearchType(typeCode)); + } + + IType SearchType(KnownTypeCode typeCode) + { + KnownTypeReference typeRef = KnownTypeReference.Get(typeCode); + if (typeRef == null) + return SpecialType.UnknownType; + var typeName = new TopLevelTypeName(typeRef.Namespace, typeRef.Name, typeRef.TypeParameterCount); + foreach (IAssembly asm in compilation.Assemblies) { + var typeDef = asm.GetTypeDefinition(typeName); + if (typeDef != null) + return typeDef; + } + return new UnknownType(typeName); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MergedNamespace.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MergedNamespace.cs new file mode 100644 index 000000000..0891df1f0 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MergedNamespace.cs @@ -0,0 +1,164 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Globalization; +using System.Linq; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// A merged namespace. + /// + public sealed class MergedNamespace : INamespace + { + readonly string externAlias; + readonly ICompilation compilation; + readonly INamespace parentNamespace; + readonly INamespace[] namespaces; + Dictionary childNamespaces; + + /// + /// Creates a new merged root namespace. + /// + /// The main compilation. + /// The individual namespaces being merged. + /// The extern alias for this namespace. + public MergedNamespace(ICompilation compilation, INamespace[] namespaces, string externAlias = null) + { + if (compilation == null) + throw new ArgumentNullException("compilation"); + if (namespaces == null) + throw new ArgumentNullException("namespaces"); + this.compilation = compilation; + this.namespaces = namespaces; + this.externAlias = externAlias; + } + + /// + /// Creates a new merged child namespace. + /// + /// The parent merged namespace. + /// The individual namespaces being merged. + public MergedNamespace(INamespace parentNamespace, INamespace[] namespaces) + { + if (parentNamespace == null) + throw new ArgumentNullException("parentNamespace"); + if (namespaces == null) + throw new ArgumentNullException("namespaces"); + this.parentNamespace = parentNamespace; + this.namespaces = namespaces; + this.compilation = parentNamespace.Compilation; + this.externAlias = parentNamespace.ExternAlias; + } + + public string ExternAlias { + get { return externAlias; } + } + + public string FullName { + get { return namespaces[0].FullName; } + } + + public string Name { + get { return namespaces[0].Name; } + } + + public INamespace ParentNamespace { + get { return parentNamespace; } + } + + public IEnumerable Types { + get { + return namespaces.SelectMany(ns => ns.Types); + } + } + + public SymbolKind SymbolKind { + get { return SymbolKind.Namespace; } + } + + public ICompilation Compilation { + get { return compilation; } + } + + public IEnumerable ContributingAssemblies { + get { return namespaces.SelectMany(ns => ns.ContributingAssemblies); } + } + + public IEnumerable ChildNamespaces { + get { return GetChildNamespaces().Values; } + } + + public INamespace GetChildNamespace(string name) + { + INamespace ns; + if (GetChildNamespaces().TryGetValue(name, out ns)) + return ns; + else + return null; + } + + Dictionary GetChildNamespaces() + { + var result = LazyInit.VolatileRead(ref this.childNamespaces); + if (result != null) { + return result; + } else { + result = new Dictionary(compilation.NameComparer); + foreach (var g in namespaces.SelectMany(ns => ns.ChildNamespaces).GroupBy(ns => ns.Name, compilation.NameComparer)) { + result.Add(g.Key, new MergedNamespace(this, g.ToArray())); + } + return LazyInit.GetOrSet(ref this.childNamespaces, result); + } + } + + public ITypeDefinition GetTypeDefinition(string name, int typeParameterCount) + { + ITypeDefinition anyTypeDef = null; + foreach (var ns in namespaces) { + ITypeDefinition typeDef = ns.GetTypeDefinition(name, typeParameterCount); + if (typeDef != null) { + if (typeDef.IsPublic) { + // Prefer accessible types over non-accessible types. + return typeDef; + // || (typeDef.IsInternal && typeDef.ParentAssembly.InternalsVisibleTo(...)) + // We can't call InternalsVisibleTo() here as we don't know the correct 'current' assembly, + // and using the main assembly can cause a stack overflow if there + // are internal assembly attributes. + } + anyTypeDef = typeDef; + } + } + return anyTypeDef; + } + + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "[MergedNamespace {0}{1} (from {2} assemblies)]", + externAlias != null ? externAlias + "::" : null, this.FullName, this.namespaces.Length); + } + + public ISymbolReference ToReference() + { + return new MergedNamespaceReference(externAlias, FullName); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MinimalCorlib.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MinimalCorlib.cs new file mode 100644 index 000000000..a28302b91 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MinimalCorlib.cs @@ -0,0 +1,65 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Resolve context represents the minimal mscorlib required for evaluating constants. + /// This contains all known types () and no other types. + /// + public sealed class MinimalCorlib : DefaultUnresolvedAssembly + { + static readonly Lazy instance = new Lazy(() => new MinimalCorlib()); + + public static MinimalCorlib Instance { + get { return instance.Value; } + } + + public ICompilation CreateCompilation() + { + return new SimpleCompilation(new DefaultSolutionSnapshot(), this); + } + + private MinimalCorlib() : base("corlib") + { + var types = new DefaultUnresolvedTypeDefinition[KnownTypeReference.KnownTypeCodeCount]; + for (int i = 0; i < types.Length; i++) { + var typeRef = KnownTypeReference.Get((KnownTypeCode)i); + if (typeRef != null) { + types[i] = new DefaultUnresolvedTypeDefinition(typeRef.Namespace, typeRef.Name); + for (int j = 0; j < typeRef.TypeParameterCount; j++) { + types[i].TypeParameters.Add(new DefaultUnresolvedTypeParameter(SymbolKind.TypeDefinition, j)); + } + AddTypeDefinition(types[i]); + } + } + for (int i = 0; i < types.Length; i++) { + var typeRef = KnownTypeReference.Get((KnownTypeCode)i); + if (typeRef != null && typeRef.baseType != KnownTypeCode.None) { + types[i].BaseTypes.Add(types[(int)typeRef.baseType]); + if (typeRef.baseType == KnownTypeCode.ValueType && i != (int)KnownTypeCode.Enum) { + types[i].Kind = TypeKind.Struct; + } + } + } + Freeze(); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/NestedTypeReference.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/NestedTypeReference.cs new file mode 100644 index 000000000..a9fe40148 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/NestedTypeReference.cs @@ -0,0 +1,106 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Type reference used to reference nested types. + /// + [Serializable] + public sealed class NestedTypeReference : ITypeReference, ISymbolReference, ISupportsInterning + { + readonly ITypeReference declaringTypeRef; + readonly string name; + readonly int additionalTypeParameterCount; + + /// + /// Creates a new NestedTypeReference. + /// + /// Reference to the declaring type. + /// Name of the nested class + /// Number of type parameters on the inner class (without type parameters on baseTypeRef) + /// + /// must be exactly the (unbound) declaring type, not a derived type, not a parameterized type. + /// NestedTypeReference thus always resolves to a type definition, never to (partially) parameterized types. + /// + public NestedTypeReference(ITypeReference declaringTypeRef, string name, int additionalTypeParameterCount) + { + if (declaringTypeRef == null) + throw new ArgumentNullException("declaringTypeRef"); + if (name == null) + throw new ArgumentNullException("name"); + this.declaringTypeRef = declaringTypeRef; + this.name = name; + this.additionalTypeParameterCount = additionalTypeParameterCount; + } + + public ITypeReference DeclaringTypeReference { + get { return declaringTypeRef; } + } + + public string Name { + get { return name; } + } + + public int AdditionalTypeParameterCount { + get { return additionalTypeParameterCount; } + } + + public IType Resolve(ITypeResolveContext context) + { + ITypeDefinition declaringType = declaringTypeRef.Resolve(context) as ITypeDefinition; + if (declaringType != null) { + int tpc = declaringType.TypeParameterCount; + foreach (IType type in declaringType.NestedTypes) { + if (type.Name == name && type.TypeParameterCount == tpc + additionalTypeParameterCount) + return type; + } + } + return new UnknownType(null, name, additionalTypeParameterCount); + } + + ISymbol ISymbolReference.Resolve(ITypeResolveContext context) + { + var type = Resolve(context); + if (type is ITypeDefinition) + return (ISymbol)type; + return null; + } + + public override string ToString() + { + if (additionalTypeParameterCount == 0) + return declaringTypeRef + "+" + name; + else + return declaringTypeRef + "+" + name + "`" + additionalTypeParameterCount; + } + + int ISupportsInterning.GetHashCodeForInterning() + { + return declaringTypeRef.GetHashCode() ^ name.GetHashCode() ^ additionalTypeParameterCount; + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + NestedTypeReference o = other as NestedTypeReference; + return o != null && declaringTypeRef == o.declaringTypeRef && name == o.name && additionalTypeParameterCount == o.additionalTypeParameterCount; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/ResolvedAttributeBlob.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/ResolvedAttributeBlob.cs new file mode 100644 index 000000000..8c7472509 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/ResolvedAttributeBlob.cs @@ -0,0 +1,176 @@ +// +// ResolvedAttributeBlob.cs +// +// Author: +// Daniel Grunwald +// +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Diagnostics; +using System.Threading; +using ICSharpCode.NRefactory.Semantics; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + sealed class CecilResolvedAttribute : IAttribute + { + readonly ITypeResolveContext context; + readonly byte[] blob; + readonly IList ctorParameterTypes; + readonly IType attributeType; + + IMethod constructor; + volatile bool constructorResolved; + + IList positionalArguments; + IList> namedArguments; + + public CecilResolvedAttribute(ITypeResolveContext context, UnresolvedAttributeBlob unresolved) + { + this.context = context; + this.blob = unresolved.blob; + this.ctorParameterTypes = unresolved.ctorParameterTypes; + this.attributeType = unresolved.attributeType.Resolve(context); + } + + public CecilResolvedAttribute(ITypeResolveContext context, IType attributeType) + { + this.context = context; + this.attributeType = attributeType; + this.ctorParameterTypes = EmptyList.Instance; + } + + DomRegion IAttribute.Region { + get { return DomRegion.Empty; } + } + + public IType AttributeType { + get { return attributeType; } + } + + public IMethod Constructor { + get { + if (!constructorResolved) { + constructor = ResolveConstructor(); + constructorResolved = true; + } + return constructor; + } + } + + IMethod ResolveConstructor() + { + var parameterTypes = ctorParameterTypes.Resolve(context); + foreach (var ctor in attributeType.GetConstructors(m => m.Parameters.Count == parameterTypes.Count)) { + bool ok = true; + for (int i = 0; i < parameterTypes.Count; i++) { + if (!ctor.Parameters[i].Type.Equals(parameterTypes[i])) { + ok = false; + break; + } + } + if (ok) + return ctor; + } + return null; + } + + public IList PositionalArguments { + get { + var result = LazyInit.VolatileRead(ref this.positionalArguments); + if (result != null) { + return result; + } + DecodeBlob(); + return positionalArguments; + } + } + + public IList> NamedArguments { + get { + var result = LazyInit.VolatileRead(ref this.namedArguments); + if (result != null) { + return result; + } + DecodeBlob(); + return namedArguments; + } + } + + public override string ToString() + { + return "[" + attributeType.ToString() + "(...)]"; + } + + void DecodeBlob() + { + var positionalArguments = new List(); + var namedArguments = new List>(); + DecodeBlob(positionalArguments, namedArguments); + Interlocked.CompareExchange(ref this.positionalArguments, positionalArguments, null); + Interlocked.CompareExchange(ref this.namedArguments, namedArguments, null); + } + + void DecodeBlob(List positionalArguments, List> namedArguments) + { + if (blob == null) + return; + BlobReader reader = new BlobReader(blob, context.CurrentAssembly); + if (reader.ReadUInt16() != 0x0001) { + Debug.WriteLine("Unknown blob prolog"); + return; + } + foreach (var ctorParameter in ctorParameterTypes.Resolve(context)) { + ResolveResult arg; + bool isError; + try { + arg = reader.ReadFixedArg (ctorParameter); + positionalArguments.Add(arg); + isError = arg.IsError; + } catch (Exception ex) { + Debug.WriteLine("Crash during blob decoding: " + ex); + isError = true; + } + if (isError) { + // After a decoding error, we must stop decoding the blob because + // we might have read too few bytes due to the error. + // Just fill up the remaining arguments with ErrorResolveResult: + while (positionalArguments.Count < ctorParameterTypes.Count) + positionalArguments.Add(ErrorResolveResult.UnknownError); + return; + } + } + try { + ushort numNamed = reader.ReadUInt16(); + for (int i = 0; i < numNamed; i++) { + var namedArg = reader.ReadNamedArg(attributeType); + if (namedArg.Key != null) + namedArguments.Add(namedArg); + } + } catch (Exception ex) { + Debug.WriteLine("Crash during blob decoding: " + ex); + } + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/SimpleCompilation.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/SimpleCompilation.cs new file mode 100644 index 000000000..a4da92dbf --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/SimpleCompilation.cs @@ -0,0 +1,168 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Simple compilation implementation. + /// + public class SimpleCompilation : ICompilation + { + readonly ISolutionSnapshot solutionSnapshot; + readonly ITypeResolveContext context; + readonly CacheManager cacheManager = new CacheManager(); + readonly KnownTypeCache knownTypeCache; + readonly IAssembly mainAssembly; + readonly IList assemblies; + readonly IList referencedAssemblies; + INamespace rootNamespace; + + public SimpleCompilation(IUnresolvedAssembly mainAssembly, params IAssemblyReference[] assemblyReferences) + : this(new DefaultSolutionSnapshot(), mainAssembly, (IEnumerable)assemblyReferences) + { + } + + public SimpleCompilation(IUnresolvedAssembly mainAssembly, IEnumerable assemblyReferences) + : this(new DefaultSolutionSnapshot(), mainAssembly, assemblyReferences) + { + } + + public SimpleCompilation(ISolutionSnapshot solutionSnapshot, IUnresolvedAssembly mainAssembly, params IAssemblyReference[] assemblyReferences) + : this(solutionSnapshot, mainAssembly, (IEnumerable)assemblyReferences) + { + } + + public SimpleCompilation(ISolutionSnapshot solutionSnapshot, IUnresolvedAssembly mainAssembly, IEnumerable assemblyReferences) + { + if (solutionSnapshot == null) + throw new ArgumentNullException("solutionSnapshot"); + if (mainAssembly == null) + throw new ArgumentNullException("mainAssembly"); + if (assemblyReferences == null) + throw new ArgumentNullException("assemblyReferences"); + this.solutionSnapshot = solutionSnapshot; + this.context = new SimpleTypeResolveContext(this); + this.mainAssembly = mainAssembly.Resolve(context); + List assemblies = new List(); + assemblies.Add(this.mainAssembly); + List referencedAssemblies = new List(); + foreach (var asmRef in assemblyReferences) { + IAssembly asm; + try { + asm = asmRef.Resolve(context); + } catch (InvalidOperationException) { + throw new InvalidOperationException("Tried to initialize compilation with an invalid assembly reference. (Forgot to load the assembly reference ? - see CecilLoader)"); + } + if (asm != null && !assemblies.Contains(asm)) + assemblies.Add(asm); + if (asm != null && !referencedAssemblies.Contains(asm)) + referencedAssemblies.Add(asm); + } + this.assemblies = assemblies.AsReadOnly(); + this.referencedAssemblies = referencedAssemblies.AsReadOnly(); + this.knownTypeCache = new KnownTypeCache(this); + } + + public IAssembly MainAssembly { + get { + if (mainAssembly == null) + throw new InvalidOperationException("Compilation isn't initialized yet"); + return mainAssembly; + } + } + + public IList Assemblies { + get { + if (assemblies == null) + throw new InvalidOperationException("Compilation isn't initialized yet"); + return assemblies; + } + } + + public IList ReferencedAssemblies { + get { + if (referencedAssemblies == null) + throw new InvalidOperationException("Compilation isn't initialized yet"); + return referencedAssemblies; + } + } + + public ITypeResolveContext TypeResolveContext { + get { return context; } + } + + public INamespace RootNamespace { + get { + INamespace ns = LazyInit.VolatileRead(ref this.rootNamespace); + if (ns != null) { + return ns; + } else { + if (referencedAssemblies == null) + throw new InvalidOperationException("Compilation isn't initialized yet"); + return LazyInit.GetOrSet(ref this.rootNamespace, CreateRootNamespace()); + } + } + } + + protected virtual INamespace CreateRootNamespace() + { + // SimpleCompilation does not support extern aliases; but derived classes might. + // CreateRootNamespace() is virtual so that derived classes can change the global namespace. + INamespace[] namespaces = new INamespace[referencedAssemblies.Count + 1]; + namespaces[0] = mainAssembly.RootNamespace; + for (int i = 0; i < referencedAssemblies.Count; i++) { + namespaces[i + 1] = referencedAssemblies[i].RootNamespace; + } + return new MergedNamespace(this, namespaces); + } + + public CacheManager CacheManager { + get { return cacheManager; } + } + + public virtual INamespace GetNamespaceForExternAlias(string alias) + { + if (string.IsNullOrEmpty(alias)) + return this.RootNamespace; + // SimpleCompilation does not support extern aliases; but derived classes might. + return null; + } + + public IType FindType(KnownTypeCode typeCode) + { + return knownTypeCache.FindType(typeCode); + } + + public StringComparer NameComparer { + get { return StringComparer.Ordinal; } + } + + public ISolutionSnapshot SolutionSnapshot { + get { return solutionSnapshot; } + } + + public override string ToString() + { + return "[SimpleCompilation " + mainAssembly.AssemblyName + "]"; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/SimpleConstantValue.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/SimpleConstantValue.cs new file mode 100644 index 000000000..191caf6f0 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/SimpleConstantValue.cs @@ -0,0 +1,69 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.Semantics; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// A simple constant value that is independent of the resolve context. + /// + [Serializable] + public sealed class SimpleConstantValue : IConstantValue, ISupportsInterning + { + readonly ITypeReference type; + readonly object value; + + public SimpleConstantValue(ITypeReference type, object value) + { + if (type == null) + throw new ArgumentNullException("type"); + this.type = type; + this.value = value; + } + + public ResolveResult Resolve(ITypeResolveContext context) + { + return new ConstantResolveResult(type.Resolve(context), value); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", + Justification = "The C# keyword is lower case")] + public override string ToString() + { + if (value == null) + return "null"; + else if (value is bool) + return value.ToString().ToLowerInvariant(); + else + return value.ToString(); + } + + int ISupportsInterning.GetHashCodeForInterning() + { + return type.GetHashCode() ^ (value != null ? value.GetHashCode() : 0); + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + SimpleConstantValue scv = other as SimpleConstantValue; + return scv != null && type == scv.type && value == scv.value; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/SimpleInterningProvider.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/SimpleInterningProvider.cs new file mode 100644 index 000000000..bb8c8bc9a --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/SimpleInterningProvider.cs @@ -0,0 +1,143 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Runtime.CompilerServices; + +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Simple interning provider. + /// + public sealed class SimpleInterningProvider : InterningProvider + { + sealed class InterningComparer : IEqualityComparer + { + public bool Equals(ISupportsInterning x, ISupportsInterning y) + { + return x.EqualsForInterning(y); + } + + public int GetHashCode(ISupportsInterning obj) + { + return obj.GetHashCodeForInterning(); + } + } + + sealed class ListComparer : IEqualityComparer + { + public bool Equals(IEnumerable a, IEnumerable b) + { + if (a.GetType() != b.GetType()) + return false; + IEnumerator e1 = a.GetEnumerator(); + IEnumerator e2 = b.GetEnumerator(); + while (e1.MoveNext()) { + // e1 has more elements than e2; or elements are different + if (!e2.MoveNext() || e1.Current != e2.Current) + return false; + } + if (e2.MoveNext()) // e2 has more elements than e1 + return false; + // No need to dispose e1/e2: non-generic IEnumerator doesn't implement IDisposable, + // and the underlying enumerator will likely be a List.Enumerator which has an empty Dispose() method. + return true; + } + + public int GetHashCode(IEnumerable obj) + { + int hashCode = obj.GetType().GetHashCode(); + unchecked { + foreach (object o in obj) { + hashCode *= 27; + hashCode += RuntimeHelpers.GetHashCode(o); + } + } + return hashCode; + } + } + + Dictionary byValueDict = new Dictionary(); + Dictionary supportsInternDict = new Dictionary(new InterningComparer()); + Dictionary listDict = new Dictionary(new ListComparer()); + + public override ISupportsInterning Intern(ISupportsInterning obj) + { + if (obj == null) + return null; + + // ensure objects are frozen when we put them into the dictionary + // note that Freeze may change the hash code of the object + FreezableHelper.Freeze(obj); + + ISupportsInterning output; + if (supportsInternDict.TryGetValue(obj, out output)) { + return output; + } else { + supportsInternDict.Add(obj, obj); + return obj; + } + } + + public override string Intern(string text) + { + if (text == null) + return null; + + object output; + if (byValueDict.TryGetValue(text, out output)) + return (string)output; + else + return text; + } + + public override object InternValue(object obj) + { + if (obj == null) + return null; + + object output; + if (byValueDict.TryGetValue(obj, out output)) + return output; + else + return obj; + } + + public override IList InternList(IList list) + { + if (list == null) + return null; + if (list.Count == 0) + return EmptyList.Instance; + if (!list.IsReadOnly) + list = new ReadOnlyCollection(list); + IEnumerable output; + if (listDict.TryGetValue(list, out output)) + list = (IList)output; + else + listDict.Add(list, list); + return list; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedEvent.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedEvent.cs new file mode 100644 index 000000000..a1ec2675a --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedEvent.cs @@ -0,0 +1,63 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Represents a specialized IEvent (event after type substitution). + /// + public class SpecializedEvent : SpecializedMember, IEvent + { + readonly IEvent eventDefinition; + + public SpecializedEvent(IEvent eventDefinition, TypeParameterSubstitution substitution) + : base(eventDefinition) + { + this.eventDefinition = eventDefinition; + AddSubstitution(substitution); + } + + public bool CanAdd { + get { return eventDefinition.CanAdd; } + } + + public bool CanRemove { + get { return eventDefinition.CanRemove; } + } + + public bool CanInvoke { + get { return eventDefinition.CanInvoke; } + } + + IMethod addAccessor, removeAccessor, invokeAccessor; + + public IMethod AddAccessor { + get { return WrapAccessor(ref this.addAccessor, eventDefinition.AddAccessor); } + } + + public IMethod RemoveAccessor { + get { return WrapAccessor(ref this.removeAccessor, eventDefinition.RemoveAccessor); } + } + + public IMethod InvokeAccessor { + get { return WrapAccessor(ref this.invokeAccessor, eventDefinition.InvokeAccessor); } + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedField.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedField.cs new file mode 100644 index 000000000..66f8a0ad0 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedField.cs @@ -0,0 +1,61 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Represents a specialized IField (field after type substitution). + /// + public class SpecializedField : SpecializedMember, IField + { + readonly IField fieldDefinition; + + public SpecializedField(IField fieldDefinition, TypeParameterSubstitution substitution) + : base(fieldDefinition) + { + this.fieldDefinition = fieldDefinition; + AddSubstitution(substitution); + } + + public bool IsReadOnly { + get { return fieldDefinition.IsReadOnly; } + } + + public bool IsVolatile { + get { return fieldDefinition.IsVolatile; } + } + + IType IVariable.Type { + get { return this.ReturnType; } + } + + public bool IsConst { + get { return fieldDefinition.IsConst; } + } + + public bool IsFixed { + get { return fieldDefinition.IsFixed; } + } + + public object ConstantValue { + get { return fieldDefinition.ConstantValue; } + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMember.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMember.cs new file mode 100644 index 000000000..45bdcc944 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMember.cs @@ -0,0 +1,409 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading; +using ICSharpCode.NRefactory.Documentation; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Represents a SpecializedMember (a member on which type substitution has been performed). + /// + public abstract class SpecializedMember : IMember + { + protected readonly IMember baseMember; + TypeParameterSubstitution substitution; + + IType declaringType; + IType returnType; + + protected SpecializedMember(IMember memberDefinition) + { + if (memberDefinition == null) + throw new ArgumentNullException("memberDefinition"); + if (memberDefinition is SpecializedMember) + throw new ArgumentException("Member definition cannot be specialized. Please use IMember.Specialize() instead of directly constructing SpecializedMember instances."); + + this.baseMember = memberDefinition; + this.substitution = TypeParameterSubstitution.Identity; + } + + /// + /// Performs a substitution. This method may only be called by constructors in derived classes. + /// + protected void AddSubstitution(TypeParameterSubstitution newSubstitution) + { + Debug.Assert(declaringType == null); + Debug.Assert(returnType == null); + this.substitution = TypeParameterSubstitution.Compose(newSubstitution, this.substitution); + } + + [Obsolete("Use IMember.Specialize() instead")] + public static IMember Create(IMember memberDefinition, TypeParameterSubstitution substitution) + { + if (memberDefinition == null) { + return null; + } else { + return memberDefinition.Specialize(substitution); + } + } + + public virtual IMemberReference ToMemberReference() + { + return ToReference(); + } + + public virtual IMemberReference ToReference() + { + return new SpecializingMemberReference( + baseMember.ToReference(), + ToTypeReference(substitution.ClassTypeArguments), + null); + } + + ISymbolReference ISymbol.ToReference() + { + return ToReference(); + } + + internal static IList ToTypeReference(IList typeArguments) + { + if (typeArguments == null) + return null; + else + return typeArguments.Select(t => t.ToTypeReference()).ToArray(); + } + + internal IMethod WrapAccessor(ref IMethod cachingField, IMethod accessorDefinition) + { + if (accessorDefinition == null) + return null; + var result = LazyInit.VolatileRead(ref cachingField); + if (result != null) { + return result; + } else { + var sm = accessorDefinition.Specialize(substitution); + //sm.AccessorOwner = this; + return LazyInit.GetOrSet(ref cachingField, sm); + } + } + + /// + /// Gets the substitution belonging to this specialized member. + /// + public TypeParameterSubstitution Substitution { + get { return substitution; } + } + + public IType DeclaringType { + get { + var result = LazyInit.VolatileRead(ref this.declaringType); + if (result != null) + return result; + IType definitionDeclaringType = baseMember.DeclaringType; + ITypeDefinition definitionDeclaringTypeDef = definitionDeclaringType as ITypeDefinition; + if (definitionDeclaringTypeDef != null && definitionDeclaringType.TypeParameterCount > 0) { + if (substitution.ClassTypeArguments != null && substitution.ClassTypeArguments.Count == definitionDeclaringType.TypeParameterCount) { + result = new ParameterizedType(definitionDeclaringTypeDef, substitution.ClassTypeArguments); + } else { + result = new ParameterizedType(definitionDeclaringTypeDef, definitionDeclaringTypeDef.TypeParameters).AcceptVisitor(substitution); + } + } else if (definitionDeclaringType != null) { + result = definitionDeclaringType.AcceptVisitor(substitution); + } + return LazyInit.GetOrSet(ref this.declaringType, result); + } + internal set { + // This setter is used as an optimization when the code constructing + // the SpecializedMember already knows the declaring type. + Debug.Assert(this.declaringType == null); + // As this setter is used only during construction before the member is published + // to other threads, we don't need a volatile write. + this.declaringType = value; + } + } + + public IMember MemberDefinition { + get { return baseMember.MemberDefinition; } + } + + public IUnresolvedMember UnresolvedMember { + get { return baseMember.UnresolvedMember; } + } + + public IType ReturnType { + get { + var result = LazyInit.VolatileRead(ref this.returnType); + if (result != null) + return result; + else + return LazyInit.GetOrSet(ref this.returnType, baseMember.ReturnType.AcceptVisitor(substitution)); + } + protected set { + // This setter is used for LiftedUserDefinedOperator, a special case of specialized member + // (not a normal type parameter substitution). + + // As this setter is used only during construction before the member is published + // to other threads, we don't need a volatile write. + this.returnType = value; + } + } + + public bool IsVirtual { + get { return baseMember.IsVirtual; } + } + + public bool IsOverride { + get { return baseMember.IsOverride; } + } + + public bool IsOverridable { + get { return baseMember.IsOverridable; } + } + + public SymbolKind SymbolKind { + get { return baseMember.SymbolKind; } + } + + [Obsolete("Use the SymbolKind property instead.")] + public EntityType EntityType { + get { return baseMember.EntityType; } + } + + public DomRegion Region { + get { return baseMember.Region; } + } + + public DomRegion BodyRegion { + get { return baseMember.BodyRegion; } + } + + public ITypeDefinition DeclaringTypeDefinition { + get { return baseMember.DeclaringTypeDefinition; } + } + + public IList Attributes { + get { return baseMember.Attributes; } + } + + IList implementedInterfaceMembers; + + public IList ImplementedInterfaceMembers { + get { + return LazyInitializer.EnsureInitialized(ref implementedInterfaceMembers, FindImplementedInterfaceMembers); + } + } + + IList FindImplementedInterfaceMembers() + { + var definitionImplementations = baseMember.ImplementedInterfaceMembers; + IMember[] result = new IMember[definitionImplementations.Count]; + for (int i = 0; i < result.Length; i++) { + result[i] = definitionImplementations[i].Specialize(substitution); + } + return result; + } + + public bool IsExplicitInterfaceImplementation { + get { return baseMember.IsExplicitInterfaceImplementation; } + } + + public DocumentationComment Documentation { + get { return baseMember.Documentation; } + } + + public Accessibility Accessibility { + get { return baseMember.Accessibility; } + } + + public bool IsStatic { + get { return baseMember.IsStatic; } + } + + public bool IsAbstract { + get { return baseMember.IsAbstract; } + } + + public bool IsSealed { + get { return baseMember.IsSealed; } + } + + public bool IsShadowing { + get { return baseMember.IsShadowing; } + } + + public bool IsSynthetic { + get { return baseMember.IsSynthetic; } + } + + public bool IsPrivate { + get { return baseMember.IsPrivate; } + } + + public bool IsPublic { + get { return baseMember.IsPublic; } + } + + public bool IsProtected { + get { return baseMember.IsProtected; } + } + + public bool IsInternal { + get { return baseMember.IsInternal; } + } + + public bool IsProtectedOrInternal { + get { return baseMember.IsProtectedOrInternal; } + } + + public bool IsProtectedAndInternal { + get { return baseMember.IsProtectedAndInternal; } + } + + public string FullName { + get { return baseMember.FullName; } + } + + public string Name { + get { return baseMember.Name; } + } + + public string Namespace { + get { return baseMember.Namespace; } + } + + public string ReflectionName { + get { return baseMember.ReflectionName; } + } + + public ICompilation Compilation { + get { return baseMember.Compilation; } + } + + public IAssembly ParentAssembly { + get { return baseMember.ParentAssembly; } + } + + public virtual IMember Specialize(TypeParameterSubstitution newSubstitution) + { + return baseMember.Specialize(TypeParameterSubstitution.Compose(newSubstitution, this.substitution)); + } + + public override bool Equals(object obj) + { + SpecializedMember other = obj as SpecializedMember; + if (other == null) + return false; + return this.baseMember.Equals(other.baseMember) && this.substitution.Equals(other.substitution); + } + + public override int GetHashCode() + { + unchecked { + return 1000000007 * baseMember.GetHashCode() + 1000000009 * substitution.GetHashCode(); + } + } + + public override string ToString() + { + StringBuilder b = new StringBuilder("["); + b.Append(GetType().Name); + b.Append(' '); + b.Append(this.DeclaringType.ToString()); + b.Append('.'); + b.Append(this.Name); + b.Append(':'); + b.Append(this.ReturnType.ToString()); + b.Append(']'); + return b.ToString(); + } + } + + public abstract class SpecializedParameterizedMember : SpecializedMember, IParameterizedMember + { + IList parameters; + + protected SpecializedParameterizedMember(IParameterizedMember memberDefinition) + : base(memberDefinition) + { + } + + public IList Parameters { + get { + var result = LazyInit.VolatileRead(ref this.parameters); + if (result != null) + return result; + else + return LazyInit.GetOrSet(ref this.parameters, CreateParameters(this.Substitution)); + } + protected set { + // This setter is used for LiftedUserDefinedOperator, a special case of specialized member + // (not a normal type parameter substitution). + + // As this setter is used only during construction before the member is published + // to other threads, we don't need a volatile write. + this.parameters = value; + } + } + + protected IList CreateParameters(TypeVisitor substitution) + { + var paramDefs = ((IParameterizedMember)this.baseMember).Parameters; + if (paramDefs.Count == 0) { + return EmptyList.Instance; + } else { + var parameters = new IParameter[paramDefs.Count]; + for (int i = 0; i < parameters.Length; i++) { + var p = paramDefs[i]; + IType newType = p.Type.AcceptVisitor(substitution); + parameters[i] = new DefaultParameter( + newType, p.Name, this, + p.Region, p.Attributes, p.IsRef, p.IsOut, + p.IsParams, p.IsOptional, p.ConstantValue + ); + } + return Array.AsReadOnly(parameters); + } + } + + public override string ToString() + { + StringBuilder b = new StringBuilder("["); + b.Append(GetType().Name); + b.Append(' '); + b.Append(this.DeclaringType.ReflectionName); + b.Append('.'); + b.Append(this.Name); + 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(); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs new file mode 100644 index 000000000..c2fdb2d51 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs @@ -0,0 +1,286 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Represents a specialized IMethod (e.g. after type substitution). + /// + public class SpecializedMethod : SpecializedParameterizedMember, IMethod + { + readonly IMethod methodDefinition; + readonly ITypeParameter[] specializedTypeParameters; + readonly bool isParameterized; + readonly TypeParameterSubstitution substitutionWithoutSpecializedTypeParameters; + + public SpecializedMethod(IMethod methodDefinition, TypeParameterSubstitution substitution) + : base(methodDefinition) + { + if (substitution == null) + throw new ArgumentNullException("substitution"); + this.methodDefinition = methodDefinition; + this.isParameterized = substitution.MethodTypeArguments != null; + if (methodDefinition.TypeParameters.Count > 0) { + // The method is generic, so we need to specialize the type parameters + // (for specializing the constraints, and also to set the correct Owner) + specializedTypeParameters = new ITypeParameter[methodDefinition.TypeParameters.Count]; + for (int i = 0; i < specializedTypeParameters.Length; i++) { + specializedTypeParameters[i] = new SpecializedTypeParameter(methodDefinition.TypeParameters[i], this); + } + if (!isParameterized) { + // Add substitution that replaces the base method's type parameters with our specialized version + // but do this only if the type parameters on the baseMember have not already been substituted + substitutionWithoutSpecializedTypeParameters = this.Substitution; + AddSubstitution(new TypeParameterSubstitution(null, specializedTypeParameters)); + } + } + // Add the main substitution after the method type parameter specialization. + AddSubstitution(substitution); + if (substitutionWithoutSpecializedTypeParameters != null) { + // If we already have a substitution without specialized type parameters, update that: + substitutionWithoutSpecializedTypeParameters = TypeParameterSubstitution.Compose(substitution, substitutionWithoutSpecializedTypeParameters); + } else { + // Otherwise just use the whole substitution, as that doesn't contain specialized type parameters + // in this case. + substitutionWithoutSpecializedTypeParameters = this.Substitution; + } + if (specializedTypeParameters != null) { + // Set the substitution on the type parameters to the final composed substitution + foreach (var tp in specializedTypeParameters.OfType()) { + if (tp.Owner == this) + tp.substitution = base.Substitution; + } + } + } + + public IList TypeArguments { + get { return this.Substitution.MethodTypeArguments ?? EmptyList.Instance; } + } + + public bool IsParameterized { + get { return isParameterized; } + } + + public IList Parts { + get { return methodDefinition.Parts; } + } + + public IList ReturnTypeAttributes { + get { return methodDefinition.ReturnTypeAttributes; } + } + + public IList TypeParameters { + get { + return specializedTypeParameters ?? methodDefinition.TypeParameters; + } + } + + public bool IsExtensionMethod { + get { return methodDefinition.IsExtensionMethod; } + } + + public bool IsConstructor { + get { return methodDefinition.IsConstructor; } + } + + public bool IsDestructor { + get { return methodDefinition.IsDestructor; } + } + + public bool IsOperator { + get { return methodDefinition.IsOperator; } + } + + public bool IsPartial { + get { return methodDefinition.IsPartial; } + } + + public bool IsAsync { + get { return methodDefinition.IsAsync; } + } + + public bool HasBody { + get { return methodDefinition.HasBody; } + } + + public bool IsAccessor { + get { return methodDefinition.IsAccessor; } + } + + public IMethod ReducedFrom { + get { return null; } + } + + IMember accessorOwner; + + public IMember AccessorOwner { + get { + var result = LazyInit.VolatileRead(ref accessorOwner); + if (result != null) { + return result; + } else { + var ownerDefinition = methodDefinition.AccessorOwner; + if (ownerDefinition == null) + return null; + result = ownerDefinition.Specialize(this.Substitution); + return LazyInit.GetOrSet(ref accessorOwner, result); + } + } + internal set { + accessorOwner = value; + } + } + + public override IMemberReference ToReference() + { + // Pass the MethodTypeArguments to the SpecializingMemberReference only if + // the generic method itself is parameterized, not if the generic method is only + // specialized with class type arguments. + + // This is necessary due to this part of the ToMemberReference() contract: + // If this member is specialized using open generic types, the resulting member reference will need to be looked up in an appropriate generic context. + // Otherwise, the main resolve context of a compilation is sufficient. + // -> + // This means that if the method itself isn't specialized, + // we must not include TypeParameterReferences for the specialized type parameters + // in the resulting member reference. + if (isParameterized) { + return new SpecializingMemberReference( + baseMember.ToReference(), + ToTypeReference(base.Substitution.ClassTypeArguments), + ToTypeReference(base.Substitution.MethodTypeArguments)); + } else { + return base.ToReference(); + } + } + + public override IMemberReference ToMemberReference() + { + return ToReference(); + } + + public override bool Equals(object obj) + { + SpecializedMethod other = obj as SpecializedMethod; + if (other == null) + return false; + return this.baseMember.Equals(other.baseMember) && this.substitutionWithoutSpecializedTypeParameters.Equals(other.substitutionWithoutSpecializedTypeParameters); + } + + public override int GetHashCode() + { + unchecked { + return 1000000013 * baseMember.GetHashCode() + 1000000009 * substitutionWithoutSpecializedTypeParameters.GetHashCode(); + } + } + + public override IMember Specialize(TypeParameterSubstitution newSubstitution) + { + return methodDefinition.Specialize(TypeParameterSubstitution.Compose(newSubstitution, substitutionWithoutSpecializedTypeParameters)); + } + + IMethod IMethod.Specialize(TypeParameterSubstitution newSubstitution) + { + return methodDefinition.Specialize(TypeParameterSubstitution.Compose(newSubstitution, substitutionWithoutSpecializedTypeParameters)); + } + + public override string ToString() + { + StringBuilder b = new StringBuilder("["); + b.Append(GetType().Name); + b.Append(' '); + b.Append(this.DeclaringType.ReflectionName); + b.Append('.'); + b.Append(this.Name); + if (this.TypeArguments.Count > 0) { + b.Append('['); + for (int i = 0; i < this.TypeArguments.Count; i++) { + if (i > 0) b.Append(", "); + 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++) { + if (i > 0) b.Append(", "); + b.Append(this.Parameters[i].ToString()); + } + b.Append("):"); + b.Append(this.ReturnType.ReflectionName); + b.Append(']'); + return b.ToString(); + } + + sealed class SpecializedTypeParameter : AbstractTypeParameter + { + readonly ITypeParameter baseTp; + + // The substition is set at the end of SpecializedMethod constructor + internal TypeVisitor substitution; + + public SpecializedTypeParameter(ITypeParameter baseTp, IMethod specializedOwner) + : base(specializedOwner, baseTp.Index, baseTp.Name, baseTp.Variance, baseTp.Attributes, baseTp.Region) + { + // We don't have to consider already-specialized baseTps because + // we read the baseTp directly from the unpacked memberDefinition. + this.baseTp = baseTp; + } + + public override int GetHashCode() + { + return baseTp.GetHashCode() ^ this.Owner.GetHashCode(); + } + + public override bool Equals(IType other) + { + // Compare the owner, not the substitution, because the substitution may contain this specialized type parameter recursively + SpecializedTypeParameter o = other as SpecializedTypeParameter; + return o != null && baseTp.Equals(o.baseTp) && this.Owner.Equals(o.Owner); + } + + public override bool HasValueTypeConstraint { + get { return baseTp.HasValueTypeConstraint; } + } + + public override bool HasReferenceTypeConstraint { + get { return baseTp.HasReferenceTypeConstraint; } + } + + public override bool HasDefaultConstructorConstraint { + get { return baseTp.HasDefaultConstructorConstraint; } + } + + public override IEnumerable DirectBaseTypes { + get { + return baseTp.DirectBaseTypes.Select(t => t.AcceptVisitor(substitution)); + } + } + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedProperty.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedProperty.cs new file mode 100644 index 000000000..575144991 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedProperty.cs @@ -0,0 +1,59 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Represents a specialized IProperty (property after type substitution). + /// + public class SpecializedProperty : SpecializedParameterizedMember, IProperty + { + readonly IProperty propertyDefinition; + + public SpecializedProperty(IProperty propertyDefinition, TypeParameterSubstitution substitution) + : base(propertyDefinition) + { + this.propertyDefinition = propertyDefinition; + AddSubstitution(substitution); + } + + public bool CanGet { + get { return propertyDefinition.CanGet; } + } + + public bool CanSet { + get { return propertyDefinition.CanSet; } + } + + IMethod getter, setter; + + public IMethod Getter { + get { return WrapAccessor(ref this.getter, propertyDefinition.Getter); } + } + + public IMethod Setter { + get { return WrapAccessor(ref this.setter, propertyDefinition.Setter); } + } + + public bool IsIndexer { + get { return propertyDefinition.IsIndexer; } + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializingMemberReference.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializingMemberReference.cs new file mode 100644 index 000000000..701a7f642 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializingMemberReference.cs @@ -0,0 +1,67 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + [Serializable] + public sealed class SpecializingMemberReference : IMemberReference + { + IMemberReference memberDefinitionReference; + IList classTypeArgumentReferences; + IList methodTypeArgumentReferences; + + public SpecializingMemberReference(IMemberReference memberDefinitionReference, IList classTypeArgumentReferences = null, IList methodTypeArgumentReferences = null) + { + if (memberDefinitionReference == null) + throw new ArgumentNullException("memberDefinitionReference"); + this.memberDefinitionReference = memberDefinitionReference; + this.classTypeArgumentReferences = classTypeArgumentReferences; + this.methodTypeArgumentReferences = methodTypeArgumentReferences; + } + + public IMember Resolve(ITypeResolveContext context) + { + var memberDefinition = memberDefinitionReference.Resolve(context); + if (memberDefinition == null) + return null; + return memberDefinition.Specialize( + new TypeParameterSubstitution( + classTypeArgumentReferences != null ? classTypeArgumentReferences.Resolve(context) : null, + methodTypeArgumentReferences != null ? methodTypeArgumentReferences.Resolve(context) : null + ) + ); + } + + ISymbol ISymbolReference.Resolve(ITypeResolveContext context) + { + return Resolve(context); + } + + public ITypeReference DeclaringTypeReference { + get { + if (classTypeArgumentReferences != null) + return new ParameterizedTypeReference(memberDefinitionReference.DeclaringTypeReference, classTypeArgumentReferences); + else + return memberDefinitionReference.DeclaringTypeReference; + } + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/TypeParameterReference.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/TypeParameterReference.cs new file mode 100644 index 000000000..e6ef94003 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/TypeParameterReference.cs @@ -0,0 +1,96 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Globalization; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + [Serializable] + public sealed class TypeParameterReference : ITypeReference, ISymbolReference + { + static readonly TypeParameterReference[] classTypeParameterReferences = new TypeParameterReference[8]; + static readonly TypeParameterReference[] methodTypeParameterReferences = new TypeParameterReference[8]; + + /// + /// Creates a type parameter reference. + /// For common type parameter references, this method may return a shared instance. + /// + public static TypeParameterReference Create(SymbolKind ownerType, int index) + { + if (index >= 0 && index < 8 && (ownerType == SymbolKind.TypeDefinition || ownerType == SymbolKind.Method)) { + TypeParameterReference[] arr = (ownerType == SymbolKind.TypeDefinition) ? classTypeParameterReferences : methodTypeParameterReferences; + TypeParameterReference result = LazyInit.VolatileRead(ref arr[index]); + if (result == null) { + result = LazyInit.GetOrSet(ref arr[index], new TypeParameterReference(ownerType, index)); + } + return result; + } else { + return new TypeParameterReference(ownerType, index); + } + } + + readonly SymbolKind ownerType; + readonly int index; + + public int Index { + get { + return index; + } + } + + public TypeParameterReference(SymbolKind ownerType, int index) + { + this.ownerType = ownerType; + this.index = index; + } + + public IType Resolve(ITypeResolveContext context) + { + if (ownerType == SymbolKind.Method) { + IMethod method = context.CurrentMember as IMethod; + if (method != null && index < method.TypeParameters.Count) { + return method.TypeParameters[index]; + } + return DummyTypeParameter.GetMethodTypeParameter(index); + } else if (ownerType == SymbolKind.TypeDefinition) { + ITypeDefinition typeDef = context.CurrentTypeDefinition; + if (typeDef != null && index < typeDef.TypeParameters.Count) { + return typeDef.TypeParameters[index]; + } + return DummyTypeParameter.GetClassTypeParameter(index); + } else { + return SpecialType.UnknownType; + } + } + + ISymbol ISymbolReference.Resolve(ITypeResolveContext context) + { + return Resolve(context) as ISymbol; + } + + public override string ToString() + { + if (ownerType == SymbolKind.Method) + return "!!" + index.ToString(CultureInfo.InvariantCulture); + else + return "!" + index.ToString(CultureInfo.InvariantCulture); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/TypeWithElementType.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/TypeWithElementType.cs new file mode 100644 index 000000000..afc22a08c --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/TypeWithElementType.cs @@ -0,0 +1,61 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + public abstract class TypeWithElementType : AbstractType + { + [CLSCompliant(false)] + protected IType elementType; + + protected TypeWithElementType(IType elementType) + { + if (elementType == null) + throw new ArgumentNullException("elementType"); + this.elementType = elementType; + } + + public override string Name { + get { return elementType.Name + NameSuffix; } + } + + public override string Namespace { + get { return elementType.Namespace; } + } + + public override string FullName { + get { return elementType.FullName + NameSuffix; } + } + + public override string ReflectionName { + get { return elementType.ReflectionName + NameSuffix; } + } + + public abstract string NameSuffix { get; } + + public IType ElementType { + get { return elementType; } + } + + // Force concrete implementations to override VisitChildren - the base implementation + // in AbstractType assumes there are no children, but we know there is (at least) 1. + public abstract override IType VisitChildren(TypeVisitor visitor); + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/UnknownType.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/UnknownType.cs new file mode 100644 index 000000000..e1855eb99 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/UnknownType.cs @@ -0,0 +1,117 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Diagnostics; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// An unknown type where (part) of the name is known. + /// + [Serializable] + public class UnknownType : AbstractType, ITypeReference + { + readonly bool namespaceKnown; + readonly FullTypeName fullTypeName; + + /// + /// Creates a new unknown type. + /// + /// Namespace name, if known. Can be null if unknown. + /// Name of the type, must not be null. + /// Type parameter count, zero if unknown. + public UnknownType(string namespaceName, string name, int typeParameterCount = 0) + { + if (name == null) + throw new ArgumentNullException("name"); + this.namespaceKnown = namespaceName != null; + this.fullTypeName = new TopLevelTypeName(namespaceName ?? string.Empty, name, typeParameterCount); + } + + /// + /// Creates a new unknown type. + /// + /// Full name of the unknown type. + public UnknownType(FullTypeName fullTypeName) + { + if (fullTypeName.Name == null) { + Debug.Assert(fullTypeName == default(FullTypeName)); + this.namespaceKnown = false; + this.fullTypeName = new TopLevelTypeName(string.Empty, "?", 0); + } else { + this.namespaceKnown = true; + this.fullTypeName = fullTypeName; + } + } + + public override TypeKind Kind { + get { return TypeKind.Unknown; } + } + + public override ITypeReference ToTypeReference() + { + return this; + } + + IType ITypeReference.Resolve(ITypeResolveContext context) + { + if (context == null) + throw new ArgumentNullException("context"); + return this; + } + + public override string Name { + get { return fullTypeName.Name; } + } + + public override string Namespace { + get { return fullTypeName.TopLevelTypeName.Namespace; } + } + + public override string ReflectionName { + get { return namespaceKnown ? fullTypeName.ReflectionName : "?"; } + } + + public override int TypeParameterCount { + get { return fullTypeName.TypeParameterCount; } + } + + public override bool? IsReferenceType { + get { return null; } + } + + public override int GetHashCode() + { + return (namespaceKnown ? 812571 : 12651) ^ fullTypeName.GetHashCode(); + } + + public override bool Equals(IType other) + { + UnknownType o = other as UnknownType; + if (o == null) + return false; + return this.namespaceKnown == o.namespaceKnown && this.fullTypeName == o.fullTypeName; + } + + public override string ToString() + { + return "[UnknownType " + fullTypeName.ReflectionName + "]"; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/UnresolvedAttributeBlob.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/UnresolvedAttributeBlob.cs new file mode 100644 index 000000000..a66e97934 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/UnresolvedAttributeBlob.cs @@ -0,0 +1,78 @@ +// +// UnresolvedAttributeBlob.cs +// +// Author: +// Daniel Grunwald +// +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// IUnresolvedAttribute implementation that loads the arguments from a binary blob. + /// + [Serializable] + public sealed class UnresolvedAttributeBlob : IUnresolvedAttribute, ISupportsInterning + { + internal readonly ITypeReference attributeType; + internal readonly IList ctorParameterTypes; + internal readonly byte[] blob; + + public UnresolvedAttributeBlob(ITypeReference attributeType, IList ctorParameterTypes, byte[] blob) + { + if (attributeType == null) + throw new ArgumentNullException("attributeType"); + if (ctorParameterTypes == null) + throw new ArgumentNullException("ctorParameterTypes"); + if (blob == null) + throw new ArgumentNullException("blob"); + this.attributeType = attributeType; + this.ctorParameterTypes = ctorParameterTypes; + this.blob = blob; + } + + DomRegion IUnresolvedAttribute.Region { + get { return DomRegion.Empty; } + } + + public IAttribute CreateResolvedAttribute(ITypeResolveContext context) + { + if (context.CurrentAssembly == null) + throw new InvalidOperationException("Cannot resolve CecilUnresolvedAttribute without a parent assembly"); + return new CecilResolvedAttribute(context, this); + } + + int ISupportsInterning.GetHashCodeForInterning() + { + return attributeType.GetHashCode() ^ ctorParameterTypes.GetHashCode() ^ BlobReader.GetBlobHashCode(blob); + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + UnresolvedAttributeBlob o = other as UnresolvedAttributeBlob; + return o != null && attributeType == o.attributeType && ctorParameterTypes == o.ctorParameterTypes + && BlobReader.BlobEquals(blob, o.blob); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/UnresolvedSecurityDeclarationBlob.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/UnresolvedSecurityDeclarationBlob.cs new file mode 100644 index 000000000..0b4bc2cb8 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/UnresolvedSecurityDeclarationBlob.cs @@ -0,0 +1,152 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Diagnostics; +using ICSharpCode.NRefactory.Semantics; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + [Serializable] + public sealed class UnresolvedSecurityDeclarationBlob + { + static readonly ITypeReference securityActionTypeReference = typeof(System.Security.Permissions.SecurityAction).ToTypeReference(); + static readonly ITypeReference permissionSetAttributeTypeReference = typeof(System.Security.Permissions.PermissionSetAttribute).ToTypeReference(); + + readonly IConstantValue securityAction; + readonly byte[] blob; + readonly IList unresolvedAttributes = new List(); + + public UnresolvedSecurityDeclarationBlob(int securityAction, byte[] blob) + { + BlobReader reader = new BlobReader(blob, null); + this.securityAction = new SimpleConstantValue(securityActionTypeReference, securityAction); + this.blob = blob; + if (reader.ReadByte() == '.') { + // binary attribute + uint attributeCount = reader.ReadCompressedUInt32(); + for (uint i = 0; i < attributeCount; i++) { + unresolvedAttributes.Add(new UnresolvedSecurityAttribute(this, (int)i)); + } + } else { + // for backward compatibility with .NET 1.0: XML-encoded attribute + var attr = new DefaultUnresolvedAttribute(permissionSetAttributeTypeReference); + attr.ConstructorParameterTypes.Add(securityActionTypeReference); + attr.PositionalArguments.Add(this.securityAction); + string xml = System.Text.Encoding.Unicode.GetString(blob); + attr.AddNamedPropertyArgument("XML", new SimpleConstantValue(KnownTypeReference.String, xml)); + unresolvedAttributes.Add(attr); + } + } + + public IList UnresolvedAttributes { + get { return unresolvedAttributes; } + } + + public IList Resolve(IAssembly currentAssembly) + { + // TODO: make this a per-assembly cache +// CacheManager cache = currentAssembly.Compilation.CacheManager; +// IList result = (IList)cache.GetShared(this); +// if (result != null) +// return result; + + ITypeResolveContext context = new SimpleTypeResolveContext(currentAssembly); + BlobReader reader = new BlobReader(blob, currentAssembly); + if (reader.ReadByte() != '.') { + // should not use UnresolvedSecurityDeclaration for XML secdecls + throw new InvalidOperationException(); + } + ResolveResult securityActionRR = securityAction.Resolve(context); + uint attributeCount = reader.ReadCompressedUInt32(); + IAttribute[] attributes = new IAttribute[attributeCount]; + try { + ReadSecurityBlob(reader, attributes, context, securityActionRR); + } catch (NotSupportedException ex) { + // ignore invalid blobs + Debug.WriteLine(ex.ToString()); + } + for (int i = 0; i < attributes.Length; i++) { + if (attributes[i] == null) + attributes[i] = new CecilResolvedAttribute(context, SpecialType.UnknownType); + } + return attributes; +// return (IList)cache.GetOrAddShared(this, attributes); + } + + void ReadSecurityBlob(BlobReader reader, IAttribute[] attributes, ITypeResolveContext context, ResolveResult securityActionRR) + { + for (int i = 0; i < attributes.Length; i++) { + string attributeTypeName = reader.ReadSerString(); + ITypeReference attributeTypeRef = ReflectionHelper.ParseReflectionName(attributeTypeName); + IType attributeType = attributeTypeRef.Resolve(context); + + reader.ReadCompressedUInt32(); // ?? + // The specification seems to be incorrect here, so I'm using the logic from Cecil instead. + uint numNamed = reader.ReadCompressedUInt32(); + + var namedArgs = new List>((int)numNamed); + for (uint j = 0; j < numNamed; j++) { + var namedArg = reader.ReadNamedArg(attributeType); + if (namedArg.Key != null) + namedArgs.Add(namedArg); + + } + attributes[i] = new DefaultAttribute( + attributeType, + positionalArguments: new ResolveResult[] { securityActionRR }, + namedArguments: namedArgs); + } + } + } + + [Serializable] + sealed class UnresolvedSecurityAttribute : IUnresolvedAttribute, ISupportsInterning + { + readonly UnresolvedSecurityDeclarationBlob secDecl; + readonly int index; + + public UnresolvedSecurityAttribute(UnresolvedSecurityDeclarationBlob secDecl, int index) + { + Debug.Assert(secDecl != null); + this.secDecl = secDecl; + this.index = index; + } + + DomRegion IUnresolvedAttribute.Region { + get { return DomRegion.Empty; } + } + + IAttribute IUnresolvedAttribute.CreateResolvedAttribute(ITypeResolveContext context) + { + return secDecl.Resolve(context.CurrentAssembly)[index]; + } + + int ISupportsInterning.GetHashCodeForInterning() + { + return index ^ secDecl.GetHashCode(); + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + UnresolvedSecurityAttribute attr = other as UnresolvedSecurityAttribute; + return attr != null && index == attr.index && secDecl == attr.secDecl; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/VoidTypeDefinition.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/VoidTypeDefinition.cs new file mode 100644 index 000000000..eba354cbc --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/VoidTypeDefinition.cs @@ -0,0 +1,73 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Special type definition for 'void'. + /// + public class VoidTypeDefinition : DefaultResolvedTypeDefinition + { + public VoidTypeDefinition(ITypeResolveContext parentContext, params IUnresolvedTypeDefinition[] parts) + : base(parentContext, parts) + { + } + + public override TypeKind Kind { + get { return TypeKind.Void; } + } + + public override IEnumerable GetConstructors(Predicate filter, GetMemberOptions options) + { + return EmptyList.Instance; + } + + public override IEnumerable GetEvents(Predicate filter, GetMemberOptions options) + { + return EmptyList.Instance; + } + + public override IEnumerable GetFields(Predicate filter, GetMemberOptions options) + { + return EmptyList.Instance; + } + + public override IEnumerable GetMethods(Predicate filter, GetMemberOptions options) + { + return EmptyList.Instance; + } + + public override IEnumerable GetMethods(IList typeArguments, Predicate filter, GetMemberOptions options) + { + return EmptyList.Instance; + } + + public override IEnumerable GetProperties(Predicate filter, GetMemberOptions options) + { + return EmptyList.Instance; + } + + public override IEnumerable GetMembers(Predicate filter, GetMemberOptions options) + { + return EmptyList.Instance; + } + } +} \ No newline at end of file diff --git a/ICSharpCode.Decompiler/TypeSystem/InheritanceHelper.cs b/ICSharpCode.Decompiler/TypeSystem/InheritanceHelper.cs new file mode 100644 index 000000000..b4f272a6c --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/InheritanceHelper.cs @@ -0,0 +1,152 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; +using ICSharpCode.NRefactory.TypeSystem.Implementation; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Provides helper methods for inheritance. + /// + public static class InheritanceHelper + { + // TODO: maybe these should be extension methods? + // or even part of the interface itself? (would allow for easy caching) + + #region GetBaseMember + /// + /// Gets the base member that has the same signature. + /// + public static IMember GetBaseMember(IMember member) + { + return GetBaseMembers(member, false).FirstOrDefault(); + } + + /// + /// Gets all base members that have the same signature. + /// + /// + /// List of base members with the same signature. The member from the derived-most base class is returned first. + /// + public static IEnumerable GetBaseMembers(IMember member, bool includeImplementedInterfaces) + { + if (member == null) + throw new ArgumentNullException("member"); + + if (member.IsExplicitInterfaceImplementation && member.ImplementedInterfaceMembers.Count == 1) { + // C#-style explicit interface implementation + member = member.ImplementedInterfaceMembers[0]; + yield return member; + } + + // Remove generic specialization + var substitution = member.Substitution; + member = member.MemberDefinition; + + if (member.DeclaringTypeDefinition == null) { + // For global methods, return empty list. (prevent SharpDevelop UDC crash 4524) + yield break; + } + + IEnumerable allBaseTypes; + if (includeImplementedInterfaces) { + allBaseTypes = member.DeclaringTypeDefinition.GetAllBaseTypes(); + } else { + allBaseTypes = member.DeclaringTypeDefinition.GetNonInterfaceBaseTypes(); + } + foreach (IType baseType in allBaseTypes.Reverse()) { + if (baseType == member.DeclaringTypeDefinition) + continue; + + IEnumerable baseMembers; + if (member.SymbolKind == SymbolKind.Accessor) { + baseMembers = baseType.GetAccessors(m => m.Name == member.Name && !m.IsExplicitInterfaceImplementation, GetMemberOptions.IgnoreInheritedMembers); + } else { + baseMembers = baseType.GetMembers(m => m.Name == member.Name && !m.IsExplicitInterfaceImplementation, GetMemberOptions.IgnoreInheritedMembers); + } + foreach (IMember baseMember in baseMembers) { + if (baseMember.IsPrivate) { + // skip private base members; + continue; + } + if (SignatureComparer.Ordinal.Equals(member, baseMember)) { + yield return baseMember.Specialize(substitution); + } + } + } + } + #endregion + + #region GetDerivedMember + /// + /// Finds the member declared in 'derivedType' that has the same signature (could override) 'baseMember'. + /// + public static IMember GetDerivedMember(IMember baseMember, ITypeDefinition derivedType) + { + if (baseMember == null) + throw new ArgumentNullException("baseMember"); + if (derivedType == null) + throw new ArgumentNullException("derivedType"); + + if (baseMember.Compilation != derivedType.Compilation) + throw new ArgumentException("baseMember and derivedType must be from the same compilation"); + + baseMember = baseMember.MemberDefinition; + bool includeInterfaces = baseMember.DeclaringTypeDefinition.Kind == TypeKind.Interface; + IMethod method = baseMember as IMethod; + if (method != null) { + foreach (IMethod derivedMethod in derivedType.Methods) { + if (derivedMethod.Name == method.Name && derivedMethod.Parameters.Count == method.Parameters.Count) { + if (derivedMethod.TypeParameters.Count == method.TypeParameters.Count) { + // The method could override the base method: + if (GetBaseMembers(derivedMethod, includeInterfaces).Any(m => m.MemberDefinition == baseMember)) + return derivedMethod; + } + } + } + } + IProperty property = baseMember as IProperty; + if (property != null) { + foreach (IProperty derivedProperty in derivedType.Properties) { + if (derivedProperty.Name == property.Name && derivedProperty.Parameters.Count == property.Parameters.Count) { + // The property could override the base property: + if (GetBaseMembers(derivedProperty, includeInterfaces).Any(m => m.MemberDefinition == baseMember)) + return derivedProperty; + } + } + } + if (baseMember is IEvent) { + foreach (IEvent derivedEvent in derivedType.Events) { + if (derivedEvent.Name == baseMember.Name) + return derivedEvent; + } + } + if (baseMember is IField) { + foreach (IField derivedField in derivedType.Fields) { + if (derivedField.Name == baseMember.Name) + return derivedField; + } + } + return null; + } + #endregion + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/IntersectionType.cs b/ICSharpCode.Decompiler/TypeSystem/IntersectionType.cs new file mode 100644 index 000000000..f273208e0 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/IntersectionType.cs @@ -0,0 +1,178 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Collections.ObjectModel; +using System.Diagnostics; +using System.Linq; +using System.Text; + +using ICSharpCode.NRefactory.TypeSystem.Implementation; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Represents the intersection of several types. + /// + public class IntersectionType : AbstractType + { + readonly ReadOnlyCollection types; + + public ReadOnlyCollection Types { + get { return types; } + } + + private IntersectionType(IType[] types) + { + Debug.Assert(types.Length >= 2); + this.types = Array.AsReadOnly(types); + } + + public static IType Create(IEnumerable types) + { + IType[] arr = types.Distinct().ToArray(); + foreach (IType type in arr) { + if (type == null) + throw new ArgumentNullException(); + } + if (arr.Length == 0) + return SpecialType.UnknownType; + else if (arr.Length == 1) + return arr[0]; + else + return new IntersectionType(arr); + } + + public override TypeKind Kind { + get { return TypeKind.Intersection; } + } + + public override string Name { + get { + StringBuilder b = new StringBuilder(); + foreach (var t in types) { + if (b.Length > 0) + b.Append(" & "); + b.Append(t.Name); + } + return b.ToString(); + } + } + + public override string ReflectionName { + get { + StringBuilder b = new StringBuilder(); + foreach (var t in types) { + if (b.Length > 0) + b.Append(" & "); + b.Append(t.ReflectionName); + } + return b.ToString(); + } + } + + public override bool? IsReferenceType { + get { + foreach (var t in types) { + bool? isReferenceType = t.IsReferenceType; + if (isReferenceType.HasValue) + return isReferenceType.Value; + } + return null; + } + } + + public override int GetHashCode() + { + int hashCode = 0; + unchecked { + foreach (var t in types) { + hashCode *= 7137517; + hashCode += t.GetHashCode(); + } + } + return hashCode; + } + + public override bool Equals(IType other) + { + IntersectionType o = other as IntersectionType; + if (o != null && types.Count == o.types.Count) { + for (int i = 0; i < types.Count; i++) { + if (!types[i].Equals(o.types[i])) + return false; + } + return true; + } + return false; + } + + public override IEnumerable DirectBaseTypes { + get { return types; } + } + + public override ITypeReference ToTypeReference() + { + throw new NotSupportedException(); + } + + public override IEnumerable GetMethods(Predicate filter, GetMemberOptions options) + { + return GetMembersHelper.GetMethods(this, FilterNonStatic(filter), options); + } + + public override IEnumerable GetMethods(IList typeArguments, Predicate filter, GetMemberOptions options) + { + return GetMembersHelper.GetMethods(this, typeArguments, filter, options); + } + + public override IEnumerable GetProperties(Predicate filter, GetMemberOptions options) + { + return GetMembersHelper.GetProperties(this, FilterNonStatic(filter), options); + } + + public override IEnumerable GetFields(Predicate filter, GetMemberOptions options) + { + return GetMembersHelper.GetFields(this, FilterNonStatic(filter), options); + } + + public override IEnumerable GetEvents(Predicate filter, GetMemberOptions options) + { + return GetMembersHelper.GetEvents(this, FilterNonStatic(filter), options); + } + + public override IEnumerable GetMembers(Predicate filter, GetMemberOptions options) + { + return GetMembersHelper.GetMembers(this, FilterNonStatic(filter), options); + } + + public override IEnumerable GetAccessors(Predicate filter, GetMemberOptions options) + { + return GetMembersHelper.GetAccessors(this, FilterNonStatic(filter), options); + } + + static Predicate FilterNonStatic(Predicate filter) where T : class, IUnresolvedMember + { + if (filter == null) + return member => !member.IsStatic; + else + return member => !member.IsStatic && filter(member); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/KnownTypeReference.cs b/ICSharpCode.Decompiler/TypeSystem/KnownTypeReference.cs new file mode 100644 index 000000000..98f3a1841 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/KnownTypeReference.cs @@ -0,0 +1,500 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Represents some well-known types. + /// + public enum KnownTypeCode + { + // Note: DefaultResolvedTypeDefinition uses (KnownTypeCode)-1 as special value for "not yet calculated". + // The order of type codes at the beginning must correspond to those in System.TypeCode. + + /// + /// Not one of the known types. + /// + None, + /// object (System.Object) + Object, + /// System.DBNull + DBNull, + /// bool (System.Boolean) + Boolean, + /// char (System.Char) + Char, + /// sbyte (System.SByte) + SByte, + /// byte (System.Byte) + Byte, + /// short (System.Int16) + Int16, + /// ushort (System.UInt16) + UInt16, + /// int (System.Int32) + Int32, + /// uint (System.UInt32) + UInt32, + /// long (System.Int64) + Int64, + /// ulong (System.UInt64) + UInt64, + /// float (System.Single) + Single, + /// double (System.Double) + Double, + /// decimal (System.Decimal) + Decimal, + /// System.DateTime + DateTime, + /// string (System.String) + String = 18, + + // String was the last element from System.TypeCode, now our additional known types start + + /// void (System.Void) + Void, + /// System.Type + Type, + /// System.Array + Array, + /// System.Attribute + Attribute, + /// System.ValueType + ValueType, + /// System.Enum + Enum, + /// System.Delegate + Delegate, + /// System.MulticastDelegate + MulticastDelegate, + /// System.Exception + Exception, + /// System.IntPtr + IntPtr, + /// System.UIntPtr + UIntPtr, + /// System.Collections.IEnumerable + IEnumerable, + /// System.Collections.IEnumerator + IEnumerator, + /// System.Collections.Generic.IEnumerable{T} + IEnumerableOfT, + /// System.Collections.Generic.IEnumerator{T} + IEnumeratorOfT, + /// System.Collections.Generic.ICollection + ICollection, + /// System.Collections.Generic.ICollection{T} + ICollectionOfT, + /// System.Collections.Generic.IList + IList, + /// System.Collections.Generic.IList{T} + IListOfT, + /// System.Collections.Generic.IReadOnlyCollection{T} + IReadOnlyCollectionOfT, + /// System.Collections.Generic.IReadOnlyList{T} + IReadOnlyListOfT, + /// System.Threading.Tasks.Task + Task, + /// System.Threading.Tasks.Task{T} + TaskOfT, + /// System.Nullable{T} + NullableOfT, + /// System.IDisposable + IDisposable, + /// System.Runtime.CompilerServices.INotifyCompletion + INotifyCompletion, + /// System.Runtime.CompilerServices.ICriticalNotifyCompletion + ICriticalNotifyCompletion, + } + + /// + /// Contains well-known type references. + /// + [Serializable] + public sealed class KnownTypeReference : ITypeReference + { + internal const int KnownTypeCodeCount = (int)KnownTypeCode.ICriticalNotifyCompletion + 1; + + static readonly KnownTypeReference[] knownTypeReferences = new KnownTypeReference[KnownTypeCodeCount] { + null, // None + new KnownTypeReference(KnownTypeCode.Object, "System", "Object", baseType: KnownTypeCode.None), + new KnownTypeReference(KnownTypeCode.DBNull, "System", "DBNull"), + new KnownTypeReference(KnownTypeCode.Boolean, "System", "Boolean", baseType: KnownTypeCode.ValueType), + new KnownTypeReference(KnownTypeCode.Char, "System", "Char", baseType: KnownTypeCode.ValueType), + new KnownTypeReference(KnownTypeCode.SByte, "System", "SByte", baseType: KnownTypeCode.ValueType), + new KnownTypeReference(KnownTypeCode.Byte, "System", "Byte", baseType: KnownTypeCode.ValueType), + new KnownTypeReference(KnownTypeCode.Int16, "System", "Int16", baseType: KnownTypeCode.ValueType), + new KnownTypeReference(KnownTypeCode.UInt16, "System", "UInt16", baseType: KnownTypeCode.ValueType), + new KnownTypeReference(KnownTypeCode.Int32, "System", "Int32", baseType: KnownTypeCode.ValueType), + new KnownTypeReference(KnownTypeCode.UInt32, "System", "UInt32", baseType: KnownTypeCode.ValueType), + new KnownTypeReference(KnownTypeCode.Int64, "System", "Int64", baseType: KnownTypeCode.ValueType), + new KnownTypeReference(KnownTypeCode.UInt64, "System", "UInt64", baseType: KnownTypeCode.ValueType), + new KnownTypeReference(KnownTypeCode.Single, "System", "Single", baseType: KnownTypeCode.ValueType), + new KnownTypeReference(KnownTypeCode.Double, "System", "Double", baseType: KnownTypeCode.ValueType), + new KnownTypeReference(KnownTypeCode.Decimal, "System", "Decimal", baseType: KnownTypeCode.ValueType), + new KnownTypeReference(KnownTypeCode.DateTime, "System", "DateTime", baseType: KnownTypeCode.ValueType), + null, + new KnownTypeReference(KnownTypeCode.String, "System", "String"), + new KnownTypeReference(KnownTypeCode.Void, "System", "Void"), + new KnownTypeReference(KnownTypeCode.Type, "System", "Type"), + new KnownTypeReference(KnownTypeCode.Array, "System", "Array"), + new KnownTypeReference(KnownTypeCode.Attribute, "System", "Attribute"), + new KnownTypeReference(KnownTypeCode.ValueType, "System", "ValueType"), + new KnownTypeReference(KnownTypeCode.Enum, "System", "Enum", baseType: KnownTypeCode.ValueType), + new KnownTypeReference(KnownTypeCode.Delegate, "System", "Delegate"), + new KnownTypeReference(KnownTypeCode.MulticastDelegate, "System", "MulticastDelegate", baseType: KnownTypeCode.Delegate), + new KnownTypeReference(KnownTypeCode.Exception, "System", "Exception"), + new KnownTypeReference(KnownTypeCode.IntPtr, "System", "IntPtr", baseType: KnownTypeCode.ValueType), + new KnownTypeReference(KnownTypeCode.UIntPtr, "System", "UIntPtr", baseType: KnownTypeCode.ValueType), + new KnownTypeReference(KnownTypeCode.IEnumerable, "System.Collections", "IEnumerable"), + new KnownTypeReference(KnownTypeCode.IEnumerator, "System.Collections", "IEnumerator"), + new KnownTypeReference(KnownTypeCode.IEnumerableOfT, "System.Collections.Generic", "IEnumerable", 1), + new KnownTypeReference(KnownTypeCode.IEnumeratorOfT, "System.Collections.Generic", "IEnumerator", 1), + new KnownTypeReference(KnownTypeCode.ICollection, "System.Collections", "ICollection"), + new KnownTypeReference(KnownTypeCode.ICollectionOfT, "System.Collections.Generic", "ICollection", 1), + new KnownTypeReference(KnownTypeCode.IList, "System.Collections", "IList"), + new KnownTypeReference(KnownTypeCode.IListOfT, "System.Collections.Generic", "IList", 1), + + new KnownTypeReference(KnownTypeCode.IReadOnlyCollectionOfT, "System.Collections.Generic", "IReadOnlyCollection", 1), + new KnownTypeReference(KnownTypeCode.IReadOnlyListOfT, "System.Collections.Generic", "IReadOnlyList", 1), + new KnownTypeReference(KnownTypeCode.Task, "System.Threading.Tasks", "Task"), + new KnownTypeReference(KnownTypeCode.TaskOfT, "System.Threading.Tasks", "Task", 1, baseType: KnownTypeCode.Task), + new KnownTypeReference(KnownTypeCode.NullableOfT, "System", "Nullable", 1, baseType: KnownTypeCode.ValueType), + new KnownTypeReference(KnownTypeCode.IDisposable, "System", "IDisposable"), + new KnownTypeReference(KnownTypeCode.INotifyCompletion, "System.Runtime.CompilerServices", "INotifyCompletion"), + new KnownTypeReference(KnownTypeCode.ICriticalNotifyCompletion, "System.Runtime.CompilerServices", "ICriticalNotifyCompletion"), + }; + + /// + /// Gets the known type reference for the specified type code. + /// Returns null for KnownTypeCode.None. + /// + public static KnownTypeReference Get(KnownTypeCode typeCode) + { + return knownTypeReferences[(int)typeCode]; + } + + /// + /// Gets a type reference pointing to the object type. + /// + public static readonly KnownTypeReference Object = Get(KnownTypeCode.Object); + + /// + /// Gets a type reference pointing to the System.DBNull type. + /// + public static readonly KnownTypeReference DBNull = Get(KnownTypeCode.DBNull); + + /// + /// Gets a type reference pointing to the bool type. + /// + public static readonly KnownTypeReference Boolean = Get(KnownTypeCode.Boolean); + + /// + /// Gets a type reference pointing to the char type. + /// + public static readonly KnownTypeReference Char = Get(KnownTypeCode.Char); + + /// + /// Gets a type reference pointing to the sbyte type. + /// + public static readonly KnownTypeReference SByte = Get(KnownTypeCode.SByte); + + /// + /// Gets a type reference pointing to the byte type. + /// + public static readonly KnownTypeReference Byte = Get(KnownTypeCode.Byte); + + /// + /// Gets a type reference pointing to the short type. + /// + public static readonly KnownTypeReference Int16 = Get(KnownTypeCode.Int16); + + /// + /// Gets a type reference pointing to the ushort type. + /// + public static readonly KnownTypeReference UInt16 = Get(KnownTypeCode.UInt16); + + /// + /// Gets a type reference pointing to the int type. + /// + public static readonly KnownTypeReference Int32 = Get(KnownTypeCode.Int32); + + /// + /// Gets a type reference pointing to the uint type. + /// + public static readonly KnownTypeReference UInt32 = Get(KnownTypeCode.UInt32); + + /// + /// Gets a type reference pointing to the long type. + /// + public static readonly KnownTypeReference Int64 = Get(KnownTypeCode.Int64); + + /// + /// Gets a type reference pointing to the ulong type. + /// + public static readonly KnownTypeReference UInt64 = Get(KnownTypeCode.UInt64); + + /// + /// Gets a type reference pointing to the float type. + /// + public static readonly KnownTypeReference Single = Get(KnownTypeCode.Single); + + /// + /// Gets a type reference pointing to the double type. + /// + public static readonly KnownTypeReference Double = Get(KnownTypeCode.Double); + + /// + /// Gets a type reference pointing to the decimal type. + /// + public static readonly KnownTypeReference Decimal = Get(KnownTypeCode.Decimal); + + /// + /// Gets a type reference pointing to the System.DateTime type. + /// + public static readonly KnownTypeReference DateTime = Get(KnownTypeCode.DateTime); + + /// + /// Gets a type reference pointing to the string type. + /// + public static readonly KnownTypeReference String = Get(KnownTypeCode.String); + + /// + /// Gets a type reference pointing to the void type. + /// + public static readonly KnownTypeReference Void = Get(KnownTypeCode.Void); + + /// + /// Gets a type reference pointing to the System.Type type. + /// + public static readonly KnownTypeReference Type = Get(KnownTypeCode.Type); + + /// + /// Gets a type reference pointing to the System.Array type. + /// + public static readonly KnownTypeReference Array = Get(KnownTypeCode.Array); + + /// + /// Gets a type reference pointing to the System.Attribute type. + /// + public static readonly KnownTypeReference Attribute = Get(KnownTypeCode.Attribute); + + /// + /// Gets a type reference pointing to the System.ValueType type. + /// + public static readonly KnownTypeReference ValueType = Get(KnownTypeCode.ValueType); + + /// + /// Gets a type reference pointing to the System.Enum type. + /// + public static readonly KnownTypeReference Enum = Get(KnownTypeCode.Enum); + + /// + /// Gets a type reference pointing to the System.Delegate type. + /// + public static readonly KnownTypeReference Delegate = Get(KnownTypeCode.Delegate); + + /// + /// Gets a type reference pointing to the System.MulticastDelegate type. + /// + public static readonly KnownTypeReference MulticastDelegate = Get(KnownTypeCode.MulticastDelegate); + + /// + /// Gets a type reference pointing to the System.Exception type. + /// + public static readonly KnownTypeReference Exception = Get(KnownTypeCode.Exception); + + /// + /// Gets a type reference pointing to the System.IntPtr type. + /// + public static readonly KnownTypeReference IntPtr = Get(KnownTypeCode.IntPtr); + + /// + /// Gets a type reference pointing to the System.UIntPtr type. + /// + public static readonly KnownTypeReference UIntPtr = Get(KnownTypeCode.UIntPtr); + + /// + /// Gets a type reference pointing to the System.Collections.IEnumerable type. + /// + public static readonly KnownTypeReference IEnumerable = Get(KnownTypeCode.IEnumerable); + + /// + /// Gets a type reference pointing to the System.Collections.IEnumerator type. + /// + public static readonly KnownTypeReference IEnumerator = Get(KnownTypeCode.IEnumerator); + + /// + /// Gets a type reference pointing to the System.Collections.Generic.IEnumerable{T} type. + /// + public static readonly KnownTypeReference IEnumerableOfT = Get(KnownTypeCode.IEnumerableOfT); + + /// + /// Gets a type reference pointing to the System.Collections.Generic.IEnumerator{T} type. + /// + public static readonly KnownTypeReference IEnumeratorOfT = Get(KnownTypeCode.IEnumeratorOfT); + + /// + /// Gets a type reference pointing to the System.Collections.ICollection type. + /// + public static readonly KnownTypeReference ICollection = Get(KnownTypeCode.ICollection); + + /// + /// Gets a type reference pointing to the System.Collections.Generic.ICollection{T} type. + /// + public static readonly KnownTypeReference ICollectionOfT = Get(KnownTypeCode.ICollectionOfT); + + /// + /// Gets a type reference pointing to the System.Collections.IList type. + /// + public static readonly KnownTypeReference IList = Get(KnownTypeCode.IList); + + /// + /// Gets a type reference pointing to the System.Collections.Generic.IList{T} type. + /// + public static readonly KnownTypeReference IListOfT = Get(KnownTypeCode.IListOfT); + + /// + /// Gets a type reference pointing to the System.Collections.Generic.IReadOnlyCollection{T} type. + /// + public static readonly KnownTypeReference IReadOnlyCollectionOfT = Get(KnownTypeCode.IReadOnlyCollectionOfT); + + /// + /// Gets a type reference pointing to the System.Collections.Generic.IReadOnlyList{T} type. + /// + public static readonly KnownTypeReference IReadOnlyListOfT = Get(KnownTypeCode.IReadOnlyListOfT); + + /// + /// Gets a type reference pointing to the System.Threading.Tasks.Task type. + /// + public static readonly KnownTypeReference Task = Get(KnownTypeCode.Task); + + /// + /// Gets a type reference pointing to the System.Threading.Tasks.Task{T} type. + /// + public static readonly KnownTypeReference TaskOfT = Get(KnownTypeCode.TaskOfT); + + /// + /// Gets a type reference pointing to the System.Nullable{T} type. + /// + public static readonly KnownTypeReference NullableOfT = Get(KnownTypeCode.NullableOfT); + + /// + /// Gets a type reference pointing to the System.IDisposable type. + /// + public static readonly KnownTypeReference IDisposable = Get(KnownTypeCode.IDisposable); + + /// + /// Gets a type reference pointing to the System.Runtime.CompilerServices.INotifyCompletion type. + /// + public static readonly KnownTypeReference INotifyCompletion = Get(KnownTypeCode.INotifyCompletion); + + /// + /// Gets a type reference pointing to the System.Runtime.CompilerServices.ICriticalNotifyCompletion type. + /// + public static readonly KnownTypeReference ICriticalNotifyCompletion = Get(KnownTypeCode.ICriticalNotifyCompletion); + + readonly KnownTypeCode knownTypeCode; + readonly string namespaceName; + readonly string name; + readonly int typeParameterCount; + internal readonly KnownTypeCode baseType; + + private KnownTypeReference(KnownTypeCode knownTypeCode, string namespaceName, string name, int typeParameterCount = 0, KnownTypeCode baseType = KnownTypeCode.Object) + { + this.knownTypeCode = knownTypeCode; + this.namespaceName = namespaceName; + this.name = name; + this.typeParameterCount = typeParameterCount; + this.baseType = baseType; + } + + public KnownTypeCode KnownTypeCode { + get { return knownTypeCode; } + } + + public string Namespace { + get { return namespaceName; } + } + + public string Name { + get { return name; } + } + + public int TypeParameterCount { + get { return typeParameterCount; } + } + + public IType Resolve(ITypeResolveContext context) + { + return context.Compilation.FindType(knownTypeCode); + } + + public override string ToString() + { + return GetCSharpNameByTypeCode(knownTypeCode) ?? (this.Namespace + "." + this.Name); + } + + /// + /// Gets the C# primitive type name from the known type code. + /// Returns null if there is no primitive name for the specified type. + /// + public static string GetCSharpNameByTypeCode(KnownTypeCode knownTypeCode) + { + switch (knownTypeCode) { + case KnownTypeCode.Object: + return "object"; + case KnownTypeCode.Boolean: + return "bool"; + case KnownTypeCode.Char: + return "char"; + case KnownTypeCode.SByte: + return "sbyte"; + case KnownTypeCode.Byte: + return "byte"; + case KnownTypeCode.Int16: + return "short"; + case KnownTypeCode.UInt16: + return "ushort"; + case KnownTypeCode.Int32: + return "int"; + case KnownTypeCode.UInt32: + return "uint"; + case KnownTypeCode.Int64: + return "long"; + case KnownTypeCode.UInt64: + return "ulong"; + case KnownTypeCode.Single: + return "float"; + case KnownTypeCode.Double: + return "double"; + case KnownTypeCode.Decimal: + return "decimal"; + case KnownTypeCode.String: + return "string"; + case KnownTypeCode.Void: + return "void"; + default: + return null; + } + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/NullableType.cs b/ICSharpCode.Decompiler/TypeSystem/NullableType.cs new file mode 100644 index 000000000..622e66435 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/NullableType.cs @@ -0,0 +1,87 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Static helper methods for working with nullable types. + /// + public static class NullableType + { + /// + /// Gets whether the specified type is a nullable type. + /// + public static bool IsNullable(IType type) + { + if (type == null) + throw new ArgumentNullException("type"); + ParameterizedType pt = type as ParameterizedType; + return pt != null && pt.TypeParameterCount == 1 && pt.GetDefinition().KnownTypeCode == KnownTypeCode.NullableOfT; + } + + public static bool IsNonNullableValueType(IType type) + { + return type.IsReferenceType == false && !IsNullable(type); + } + + /// + /// Returns the element type, if is a nullable type. + /// Otherwise, returns the type itself. + /// + public static IType GetUnderlyingType(IType type) + { + if (type == null) + throw new ArgumentNullException("type"); + ParameterizedType pt = type as ParameterizedType; + if (pt != null && pt.TypeParameterCount == 1 && pt.FullName == "System.Nullable") + return pt.GetTypeArgument(0); + else + return type; + } + + /// + /// Creates a nullable type. + /// + public static IType Create(ICompilation compilation, IType elementType) + { + if (compilation == null) + throw new ArgumentNullException("compilation"); + if (elementType == null) + throw new ArgumentNullException("elementType"); + + IType nullableType = compilation.FindType(KnownTypeCode.NullableOfT); + ITypeDefinition nullableTypeDef = nullableType.GetDefinition(); + if (nullableTypeDef != null) + return new ParameterizedType(nullableTypeDef, new [] { elementType }); + else + return nullableType; + } + + /// + /// Creates a nullable type reference. + /// + public static ParameterizedTypeReference Create(ITypeReference elementType) + { + if (elementType == null) + throw new ArgumentNullException("elementType"); + return new ParameterizedTypeReference(KnownTypeReference.NullableOfT, new [] { elementType }); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/ParameterListComparer.cs b/ICSharpCode.Decompiler/TypeSystem/ParameterListComparer.cs new file mode 100644 index 000000000..82447a516 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/ParameterListComparer.cs @@ -0,0 +1,168 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Threading; +using ICSharpCode.NRefactory.TypeSystem.Implementation; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Compares parameter lists by comparing the types of all parameters. + /// + /// + /// 'ref int' and 'out int' are considered to be equal. + /// 'object' and 'dynamic' are also equal. + /// For generic methods, "Method{T}(T a)" and "Method{S}(S b)" are considered equal. + /// However, "Method(T a)" and "Method(S b)" are not considered equal when the type parameters T and S belong to classes. + /// + public sealed class ParameterListComparer : IEqualityComparer> + { + public static readonly ParameterListComparer Instance = new ParameterListComparer(); + + sealed class NormalizeTypeVisitor : TypeVisitor + { + public override IType VisitTypeParameter(ITypeParameter type) + { + if (type.OwnerType == SymbolKind.Method) { + return DummyTypeParameter.GetMethodTypeParameter(type.Index); + } else { + return base.VisitTypeParameter(type); + } + } + + public override IType VisitTypeDefinition(ITypeDefinition type) + { + if (type.KnownTypeCode == KnownTypeCode.Object) + return SpecialType.Dynamic; + return base.VisitTypeDefinition(type); + } + } + + static readonly NormalizeTypeVisitor normalizationVisitor = new NormalizeTypeVisitor(); + + /// + /// Replaces all occurrences of method type parameters in the given type + /// by normalized type parameters. This allows comparing parameter types from different + /// generic methods. + /// + [Obsolete("Use DummyTypeParameter.NormalizeMethodTypeParameters instead if you only need to normalize type parameters. Also, consider if you need to normalize object vs. dynamic as well.")] + public IType NormalizeMethodTypeParameters(IType type) + { + return DummyTypeParameter.NormalizeMethodTypeParameters(type); + } + + public bool Equals(IList x, IList y) + { + if (x == y) + return true; + if (x == null || y == null || x.Count != y.Count) + return false; + for (int i = 0; i < x.Count; i++) { + var a = x[i]; + var b = y[i]; + if (a == null && b == null) + continue; + if (a == null || b == null) + return false; + + // We want to consider the parameter lists "Method(T a)" and "Method(S b)" as equal. + // However, the parameter types are not considered equal, as T is a different type parameter than S. + // In order to compare the method signatures, we will normalize all method type parameters. + IType aType = a.Type.AcceptVisitor(normalizationVisitor); + IType bType = b.Type.AcceptVisitor(normalizationVisitor); + + if (!aType.Equals(bType)) + return false; + } + return true; + } + + public int GetHashCode(IList obj) + { + int hashCode = obj.Count; + unchecked { + foreach (IParameter p in obj) { + hashCode *= 27; + IType type = p.Type.AcceptVisitor(normalizationVisitor); + hashCode += type.GetHashCode(); + } + } + return hashCode; + } + } + + /// + /// Compares member signatures. + /// + /// + /// This comparer checks for equal short name, equal type parameter count, and equal parameter types (using ParameterListComparer). + /// + public sealed class SignatureComparer : IEqualityComparer + { + StringComparer nameComparer; + + public SignatureComparer(StringComparer nameComparer) + { + if (nameComparer == null) + throw new ArgumentNullException("nameComparer"); + this.nameComparer = nameComparer; + } + + /// + /// Gets a signature comparer that uses an ordinal comparison for the member name. + /// + public static readonly SignatureComparer Ordinal = new SignatureComparer(StringComparer.Ordinal); + + public bool Equals(IMember x, IMember y) + { + if (x == y) + return true; + if (x == null || y == null || x.SymbolKind != y.SymbolKind || !nameComparer.Equals(x.Name, y.Name)) + return false; + IParameterizedMember px = x as IParameterizedMember; + IParameterizedMember py = y as IParameterizedMember; + if (px != null && py != null) { + IMethod mx = x as IMethod; + IMethod my = y as IMethod; + if (mx != null && my != null && mx.TypeParameters.Count != my.TypeParameters.Count) + return false; + return ParameterListComparer.Instance.Equals(px.Parameters, py.Parameters); + } else { + return true; + } + } + + public int GetHashCode(IMember obj) + { + unchecked { + int hash = (int)obj.SymbolKind * 33 + nameComparer.GetHashCode(obj.Name); + IParameterizedMember pm = obj as IParameterizedMember; + if (pm != null) { + hash *= 27; + hash += ParameterListComparer.Instance.GetHashCode(pm.Parameters); + IMethod m = pm as IMethod; + if (m != null) + hash += m.TypeParameters.Count; + } + return hash; + } + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/ParameterizedType.cs b/ICSharpCode.Decompiler/TypeSystem/ParameterizedType.cs new file mode 100644 index 000000000..10e7a984c --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/ParameterizedType.cs @@ -0,0 +1,436 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Collections.ObjectModel; +using System.Diagnostics; +using System.Linq; +using System.Text; + +using ICSharpCode.NRefactory.TypeSystem.Implementation; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// ParameterizedType represents an instance of a generic type. + /// Example: List<string> + /// + /// + /// When getting the members, this type modifies the lists so that + /// type parameters in the signatures of the members are replaced with + /// the type arguments. + /// + [Serializable] + public sealed class ParameterizedType : IType, ICompilationProvider + { + readonly ITypeDefinition genericType; + readonly IType[] typeArguments; + + public ParameterizedType(ITypeDefinition genericType, IEnumerable typeArguments) + { + if (genericType == null) + throw new ArgumentNullException("genericType"); + if (typeArguments == null) + throw new ArgumentNullException("typeArguments"); + this.genericType = genericType; + this.typeArguments = typeArguments.ToArray(); // copy input array to ensure it isn't modified + if (this.typeArguments.Length == 0) + throw new ArgumentException("Cannot use ParameterizedType with 0 type arguments."); + if (genericType.TypeParameterCount != this.typeArguments.Length) + throw new ArgumentException("Number of type arguments must match the type definition's number of type parameters"); + for (int i = 0; i < this.typeArguments.Length; i++) { + if (this.typeArguments[i] == null) + throw new ArgumentNullException("typeArguments[" + i + "]"); + ICompilationProvider p = this.typeArguments[i] as ICompilationProvider; + if (p != null && p.Compilation != genericType.Compilation) + throw new InvalidOperationException("Cannot parameterize a type with type arguments from a different compilation."); + } + } + + /// + /// Fast internal version of the constructor. (no safety checks) + /// Keeps the array that was passed and assumes it won't be modified. + /// + internal ParameterizedType(ITypeDefinition genericType, IType[] typeArguments) + { + Debug.Assert(genericType.TypeParameterCount == typeArguments.Length); + this.genericType = genericType; + this.typeArguments = typeArguments; + } + + public TypeKind Kind { + get { return genericType.Kind; } + } + + public ICompilation Compilation { + get { return genericType.Compilation; } + } + + public bool? IsReferenceType { + get { return genericType.IsReferenceType; } + } + + public IType DeclaringType { + get { + ITypeDefinition declaringTypeDef = genericType.DeclaringTypeDefinition; + if (declaringTypeDef != null && declaringTypeDef.TypeParameterCount > 0 + && declaringTypeDef.TypeParameterCount <= genericType.TypeParameterCount) + { + IType[] newTypeArgs = new IType[declaringTypeDef.TypeParameterCount]; + Array.Copy(this.typeArguments, 0, newTypeArgs, 0, newTypeArgs.Length); + return new ParameterizedType(declaringTypeDef, newTypeArgs); + } + return declaringTypeDef; + } + } + + public int TypeParameterCount { + get { return typeArguments.Length; } + } + + public string FullName { + get { return genericType.FullName; } + } + + public string Name { + get { return genericType.Name; } + } + + public string Namespace { + get { return genericType.Namespace; } + } + + public string ReflectionName { + get { + StringBuilder b = new StringBuilder(genericType.ReflectionName); + b.Append('['); + for (int i = 0; i < typeArguments.Length; i++) { + if (i > 0) + b.Append(','); + b.Append('['); + b.Append(typeArguments[i].ReflectionName); + b.Append(']'); + } + b.Append(']'); + return b.ToString(); + } + } + + public override string ToString() + { + return ReflectionName; + } + + public IList TypeArguments { + get { + return typeArguments; + } + } + + public bool IsParameterized { + get { + return true; + } + } + + /// + /// Same as 'parameterizedType.TypeArguments[index]', but is a bit more efficient (doesn't require the read-only wrapper). + /// + public IType GetTypeArgument(int index) + { + return typeArguments[index]; + } + + /// + /// Gets the definition of the generic type. + /// For ParameterizedType, this method never returns null. + /// + public ITypeDefinition GetDefinition() + { + return genericType; + } + + public ITypeReference ToTypeReference() + { + return new ParameterizedTypeReference(genericType.ToTypeReference(), typeArguments.Select(t => t.ToTypeReference())); + } + + /// + /// Gets a type visitor that performs the substitution of class type parameters with the type arguments + /// of this parameterized type. + /// + public TypeParameterSubstitution GetSubstitution() + { + return new TypeParameterSubstitution(typeArguments, null); + } + + /// + /// Gets a type visitor that performs the substitution of class type parameters with the type arguments + /// of this parameterized type, + /// and also substitutes method type parameters with the specified method type arguments. + /// + public TypeParameterSubstitution GetSubstitution(IList methodTypeArguments) + { + return new TypeParameterSubstitution(typeArguments, methodTypeArguments); + } + + public IEnumerable DirectBaseTypes { + get { + var substitution = GetSubstitution(); + return genericType.DirectBaseTypes.Select(t => t.AcceptVisitor(substitution)); + } + } + + public IEnumerable GetNestedTypes(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) + return genericType.GetNestedTypes(filter, options); + else + return GetMembersHelper.GetNestedTypes(this, filter, options); + } + + public IEnumerable GetNestedTypes(IList typeArguments, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) + return genericType.GetNestedTypes(typeArguments, filter, options); + else + return GetMembersHelper.GetNestedTypes(this, typeArguments, filter, options); + } + + public IEnumerable GetConstructors(Predicate filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers) + { + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) + return genericType.GetConstructors(filter, options); + else + return GetMembersHelper.GetConstructors(this, filter, options); + } + + public IEnumerable GetMethods(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) + return genericType.GetMethods(filter, options); + else + return GetMembersHelper.GetMethods(this, filter, options); + } + + public IEnumerable GetMethods(IList typeArguments, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) + return genericType.GetMethods(typeArguments, filter, options); + else + return GetMembersHelper.GetMethods(this, typeArguments, filter, options); + } + + public IEnumerable GetProperties(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) + return genericType.GetProperties(filter, options); + else + return GetMembersHelper.GetProperties(this, filter, options); + } + + public IEnumerable GetFields(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) + return genericType.GetFields(filter, options); + else + return GetMembersHelper.GetFields(this, filter, options); + } + + public IEnumerable GetEvents(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) + return genericType.GetEvents(filter, options); + else + return GetMembersHelper.GetEvents(this, filter, options); + } + + public IEnumerable GetMembers(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) + return genericType.GetMembers(filter, options); + else + return GetMembersHelper.GetMembers(this, filter, options); + } + + public IEnumerable GetAccessors(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) + { + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) + return genericType.GetAccessors(filter, options); + else + return GetMembersHelper.GetAccessors(this, filter, options); + } + + public override bool Equals(object obj) + { + return Equals(obj as IType); + } + + public bool Equals(IType other) + { + ParameterizedType c = other as ParameterizedType; + if (c == null || !genericType.Equals(c.genericType) || typeArguments.Length != c.typeArguments.Length) + return false; + for (int i = 0; i < typeArguments.Length; i++) { + if (!typeArguments[i].Equals(c.typeArguments[i])) + return false; + } + return true; + } + + public override int GetHashCode() + { + int hashCode = genericType.GetHashCode(); + unchecked { + foreach (var ta in typeArguments) { + hashCode *= 1000000007; + hashCode += 1000000009 * ta.GetHashCode(); + } + } + return hashCode; + } + + public IType AcceptVisitor(TypeVisitor visitor) + { + return visitor.VisitParameterizedType(this); + } + + public IType VisitChildren(TypeVisitor visitor) + { + IType g = genericType.AcceptVisitor(visitor); + ITypeDefinition def = g as ITypeDefinition; + if (def == null) + return g; + // Keep ta == null as long as no elements changed, allocate the array only if necessary. + IType[] ta = (g != genericType) ? new IType[typeArguments.Length] : null; + for (int i = 0; i < typeArguments.Length; i++) { + IType r = typeArguments[i].AcceptVisitor(visitor); + if (r == null) + throw new NullReferenceException("TypeVisitor.Visit-method returned null"); + if (ta == null && r != typeArguments[i]) { + // we found a difference, so we need to allocate the array + ta = new IType[typeArguments.Length]; + for (int j = 0; j < i; j++) { + ta[j] = typeArguments[j]; + } + } + if (ta != null) + ta[i] = r; + } + if (def == genericType && ta == null) + return this; + else + return new ParameterizedType(def, ta ?? typeArguments); + } + } + + /// + /// ParameterizedTypeReference is a reference to generic class that specifies the type parameters. + /// Example: List<string> + /// + [Serializable] + public sealed class ParameterizedTypeReference : ITypeReference, ISupportsInterning + { + readonly ITypeReference genericType; + readonly ITypeReference[] typeArguments; + + public ParameterizedTypeReference(ITypeReference genericType, IEnumerable typeArguments) + { + if (genericType == null) + throw new ArgumentNullException("genericType"); + if (typeArguments == null) + throw new ArgumentNullException("typeArguments"); + this.genericType = genericType; + this.typeArguments = typeArguments.ToArray(); + for (int i = 0; i < this.typeArguments.Length; i++) { + if (this.typeArguments[i] == null) + throw new ArgumentNullException("typeArguments[" + i + "]"); + } + } + + public ITypeReference GenericType { + get { return genericType; } + } + + public ReadOnlyCollection TypeArguments { + get { + return Array.AsReadOnly(typeArguments); + } + } + + public IType Resolve(ITypeResolveContext context) + { + IType baseType = genericType.Resolve(context); + ITypeDefinition baseTypeDef = baseType.GetDefinition(); + if (baseTypeDef == null) + return baseType; + int tpc = baseTypeDef.TypeParameterCount; + if (tpc == 0) + return baseTypeDef; + IType[] resolvedTypes = new IType[tpc]; + for (int i = 0; i < resolvedTypes.Length; i++) { + if (i < typeArguments.Length) + resolvedTypes[i] = typeArguments[i].Resolve(context); + else + resolvedTypes[i] = SpecialType.UnknownType; + } + return new ParameterizedType(baseTypeDef, resolvedTypes); + } + + public override string ToString() + { + StringBuilder b = new StringBuilder(genericType.ToString()); + b.Append('['); + for (int i = 0; i < typeArguments.Length; i++) { + if (i > 0) + b.Append(','); + b.Append('['); + b.Append(typeArguments[i].ToString()); + b.Append(']'); + } + b.Append(']'); + return b.ToString(); + } + + int ISupportsInterning.GetHashCodeForInterning() + { + int hashCode = genericType.GetHashCode(); + unchecked { + foreach (ITypeReference t in typeArguments) { + hashCode *= 27; + hashCode += t.GetHashCode(); + } + } + return hashCode; + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + ParameterizedTypeReference o = other as ParameterizedTypeReference; + if (o != null && genericType == o.genericType && typeArguments.Length == o.typeArguments.Length) { + for (int i = 0; i < typeArguments.Length; i++) { + if (typeArguments[i] != o.typeArguments[i]) + return false; + } + return true; + } + return false; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/PointerType.cs b/ICSharpCode.Decompiler/TypeSystem/PointerType.cs new file mode 100644 index 000000000..9ad523bc1 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/PointerType.cs @@ -0,0 +1,113 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Implementation; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + public sealed class PointerType : TypeWithElementType + { + public PointerType(IType elementType) : base(elementType) + { + } + + public override TypeKind Kind { + get { return TypeKind.Pointer; } + } + + public override string NameSuffix { + get { + return "*"; + } + } + + public override bool? IsReferenceType { + get { return null; } + } + + public override int GetHashCode() + { + return elementType.GetHashCode() ^ 91725811; + } + + public override bool Equals(IType other) + { + PointerType a = other as PointerType; + return a != null && elementType.Equals(a.elementType); + } + + public override IType AcceptVisitor(TypeVisitor visitor) + { + return visitor.VisitPointerType(this); + } + + public override IType VisitChildren(TypeVisitor visitor) + { + IType e = elementType.AcceptVisitor(visitor); + if (e == elementType) + return this; + else + return new PointerType(e); + } + + public override ITypeReference ToTypeReference() + { + return new PointerTypeReference(elementType.ToTypeReference()); + } + } + + [Serializable] + public sealed class PointerTypeReference : ITypeReference, ISupportsInterning + { + readonly ITypeReference elementType; + + public PointerTypeReference(ITypeReference elementType) + { + if (elementType == null) + throw new ArgumentNullException("elementType"); + this.elementType = elementType; + } + + public ITypeReference ElementType { + get { return elementType; } + } + + public IType Resolve(ITypeResolveContext context) + { + return new PointerType(elementType.Resolve(context)); + } + + public override string ToString() + { + return elementType.ToString() + "*"; + } + + int ISupportsInterning.GetHashCodeForInterning() + { + return elementType.GetHashCode() ^ 91725812; + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + PointerTypeReference o = other as PointerTypeReference; + return o != null && this.elementType == o.elementType; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/ProjectReference.cs b/ICSharpCode.Decompiler/TypeSystem/ProjectReference.cs new file mode 100644 index 000000000..cd79aa309 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/ProjectReference.cs @@ -0,0 +1,56 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// References another project content in the same solution. + /// Using the class requires that you + /// + [Serializable] + public class ProjectReference : IAssemblyReference + { + readonly string projectFileName; + + /// + /// Creates a new reference to the specified project (must be part of the same solution). + /// + /// Full path to the file name. Must be identical to of the target project; do not use a relative path. + public ProjectReference(string projectFileName) + { + this.projectFileName = projectFileName; + } + + public IAssembly Resolve(ITypeResolveContext context) + { + var solution = context.Compilation.SolutionSnapshot; + var pc = solution.GetProjectContent(projectFileName); + if (pc != null) + return pc.Resolve(context); + else + return null; + } + + public override string ToString() + { + return string.Format("[ProjectReference {0}]", projectFileName); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/ReflectionHelper.cs b/ICSharpCode.Decompiler/TypeSystem/ReflectionHelper.cs new file mode 100644 index 000000000..3352650a2 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/ReflectionHelper.cs @@ -0,0 +1,424 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Text; +using ICSharpCode.NRefactory.TypeSystem.Implementation; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Static helper methods for reflection names. + /// + public static class ReflectionHelper + { + /// + /// A reflection class used to represent null. + /// + public sealed class Null {} + + /// + /// A reflection class used to represent dynamic. + /// + public sealed class Dynamic {} + + /// + /// A reflection class used to represent an unbound type argument. + /// + public sealed class UnboundTypeArgument {} + + #region ICompilation.FindType + /// + /// Retrieves the specified type in this compilation. + /// Returns if the type cannot be found in this compilation. + /// + /// + /// This method cannot be used with open types; all type parameters will be substituted + /// with . + /// + public static IType FindType(this ICompilation compilation, Type type) + { + return type.ToTypeReference().Resolve(compilation.TypeResolveContext); + } + #endregion + + #region Type.ToTypeReference() + /// + /// Creates a reference to the specified type. + /// + /// The type to be converted. + /// Returns the type reference. + /// + /// If the type is open (contains type parameters '`0' or '``0'), + /// an with the appropriate CurrentTypeDefinition/CurrentMember is required + /// to resolve the type reference. + /// For closed types, the root type resolve context for the compilation is sufficient. + /// + public static ITypeReference ToTypeReference(this Type type) + { + if (type == null) + return SpecialType.UnknownType; + if (type.IsGenericType && !type.IsGenericTypeDefinition) { + ITypeReference def = ToTypeReference(type.GetGenericTypeDefinition()); + Type[] arguments = type.GetGenericArguments(); + ITypeReference[] args = new ITypeReference[arguments.Length]; + bool allUnbound = true; + for (int i = 0; i < arguments.Length; i++) { + args[i] = ToTypeReference(arguments[i]); + allUnbound &= args[i].Equals(SpecialType.UnboundTypeArgument); + } + if (allUnbound) + return def; + else + return new ParameterizedTypeReference(def, args); + } else if (type.IsArray) { + return new ArrayTypeReference(ToTypeReference(type.GetElementType()), type.GetArrayRank()); + } else if (type.IsPointer) { + return new PointerTypeReference(ToTypeReference(type.GetElementType())); + } else if (type.IsByRef) { + return new ByReferenceTypeReference(ToTypeReference(type.GetElementType())); + } else if (type.IsGenericParameter) { + if (type.DeclaringMethod != null) { + return TypeParameterReference.Create(SymbolKind.Method, type.GenericParameterPosition); + } else { + return TypeParameterReference.Create(SymbolKind.TypeDefinition, type.GenericParameterPosition); + } + } else if (type.DeclaringType != null) { + if (type == typeof(Dynamic)) + return SpecialType.Dynamic; + else if (type == typeof(Null)) + return SpecialType.NullType; + else if (type == typeof(UnboundTypeArgument)) + return SpecialType.UnboundTypeArgument; + ITypeReference baseTypeRef = ToTypeReference(type.DeclaringType); + int typeParameterCount; + string name = SplitTypeParameterCountFromReflectionName(type.Name, out typeParameterCount); + return new NestedTypeReference(baseTypeRef, name, typeParameterCount); + } else { + IAssemblyReference assemblyReference = new DefaultAssemblyReference(type.Assembly.FullName); + int typeParameterCount; + string name = SplitTypeParameterCountFromReflectionName(type.Name, out typeParameterCount); + return new GetClassTypeReference(assemblyReference, type.Namespace, name, typeParameterCount); + } + } + #endregion + + #region SplitTypeParameterCountFromReflectionName + /// + /// Removes the ` with type parameter count from the reflection name. + /// + /// Do not use this method with the full name of inner classes. + public static string SplitTypeParameterCountFromReflectionName(string reflectionName) + { + int pos = reflectionName.LastIndexOf('`'); + if (pos < 0) { + return reflectionName; + } else { + return reflectionName.Substring(0, pos); + } + } + + /// + /// Removes the ` with type parameter count from the reflection name. + /// + /// Do not use this method with the full name of inner classes. + public static string SplitTypeParameterCountFromReflectionName(string reflectionName, out int typeParameterCount) + { + int pos = reflectionName.LastIndexOf('`'); + if (pos < 0) { + typeParameterCount = 0; + return reflectionName; + } else { + string typeCount = reflectionName.Substring(pos + 1); + if (int.TryParse(typeCount, out typeParameterCount)) + return reflectionName.Substring(0, pos); + else + return reflectionName; + } + } + #endregion + + #region TypeCode support + /// + /// Retrieves a built-in type using the specified type code. + /// + public static IType FindType(this ICompilation compilation, TypeCode typeCode) + { + return compilation.FindType((KnownTypeCode)typeCode); + } + + /// + /// Creates a reference to the specified type. + /// + /// The type to be converted. + /// Returns the type reference. + public static ITypeReference ToTypeReference(this TypeCode typeCode) + { + return KnownTypeReference.Get((KnownTypeCode)typeCode); + } + + /// + /// Gets the type code for the specified type, or TypeCode.Empty if none of the other type codes match. + /// + public static TypeCode GetTypeCode(IType type) + { + ITypeDefinition def = type as ITypeDefinition; + if (def != null) { + KnownTypeCode typeCode = def.KnownTypeCode; + if (typeCode <= KnownTypeCode.String && typeCode != KnownTypeCode.Void) + return (TypeCode)typeCode; + else + return TypeCode.Empty; + } + return TypeCode.Empty; + } + #endregion + + #region ParseReflectionName + /// + /// Parses a reflection name into a type reference. + /// + /// The reflection name of the type. + /// A type reference that represents the reflection name. + /// The syntax of the reflection type name is invalid + /// + /// If the type is open (contains type parameters '`0' or '``0'), + /// an with the appropriate CurrentTypeDefinition/CurrentMember is required + /// to resolve the reference to the ITypeParameter. + /// For looking up closed, assembly qualified type names, the root type resolve context for the compilation + /// is sufficient. + /// When looking up a type name that isn't assembly qualified, the type reference will look in + /// first, and if the type is not found there, + /// it will look in all other assemblies of the compilation. + /// + /// + public static ITypeReference ParseReflectionName(string reflectionTypeName) + { + if (reflectionTypeName == null) + throw new ArgumentNullException("reflectionTypeName"); + int pos = 0; + ITypeReference r = ParseReflectionName(reflectionTypeName, ref pos); + if (pos < reflectionTypeName.Length) + throw new ReflectionNameParseException(pos, "Expected end of type name"); + return r; + } + + static bool IsReflectionNameSpecialCharacter(char c) + { + switch (c) { + case '+': + case '`': + case '[': + case ']': + case ',': + case '*': + case '&': + return true; + default: + return false; + } + } + + static ITypeReference ParseReflectionName(string reflectionTypeName, ref int pos) + { + if (pos == reflectionTypeName.Length) + throw new ReflectionNameParseException(pos, "Unexpected end"); + ITypeReference reference; + if (reflectionTypeName[pos] == '`') { + // type parameter reference + pos++; + if (pos == reflectionTypeName.Length) + throw new ReflectionNameParseException(pos, "Unexpected end"); + if (reflectionTypeName[pos] == '`') { + // method type parameter reference + pos++; + int index = ReadTypeParameterCount(reflectionTypeName, ref pos); + reference = TypeParameterReference.Create(SymbolKind.Method, index); + } else { + // class type parameter reference + int index = ReadTypeParameterCount(reflectionTypeName, ref pos); + reference = TypeParameterReference.Create(SymbolKind.TypeDefinition, index); + } + } else { + // not a type parameter reference: read the actual type name + int tpc; + string typeName = ReadTypeName(reflectionTypeName, ref pos, out tpc); + string assemblyName = SkipAheadAndReadAssemblyName(reflectionTypeName, pos); + reference = CreateGetClassTypeReference(assemblyName, typeName, tpc); + } + // read type suffixes + while (pos < reflectionTypeName.Length) { + switch (reflectionTypeName[pos++]) { + case '+': + int tpc; + string typeName = ReadTypeName(reflectionTypeName, ref pos, out tpc); + reference = new NestedTypeReference(reference, typeName, tpc); + break; + case '*': + reference = new PointerTypeReference(reference); + break; + case '&': + reference = new ByReferenceTypeReference(reference); + break; + case '[': + // this might be an array or a generic type + if (pos == reflectionTypeName.Length) + throw new ReflectionNameParseException(pos, "Unexpected end"); + if (reflectionTypeName[pos] == '[') { + // it's a generic type + List typeArguments = new List(); + pos++; + typeArguments.Add(ParseReflectionName(reflectionTypeName, ref pos)); + if (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ']') + pos++; + else + throw new ReflectionNameParseException(pos, "Expected end of type argument"); + + while (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ',') { + pos++; + if (pos < reflectionTypeName.Length && reflectionTypeName[pos] == '[') + pos++; + else + throw new ReflectionNameParseException(pos, "Expected another type argument"); + + typeArguments.Add(ParseReflectionName(reflectionTypeName, ref pos)); + + if (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ']') + pos++; + else + throw new ReflectionNameParseException(pos, "Expected end of type argument"); + } + + if (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ']') { + pos++; + reference = new ParameterizedTypeReference(reference, typeArguments); + } else { + throw new ReflectionNameParseException(pos, "Expected end of generic type"); + } + } else { + // it's an array + int dimensions = 1; + while (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ',') { + dimensions++; + pos++; + } + if (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ']') { + pos++; // end of array + reference = new ArrayTypeReference(reference, dimensions); + } else { + throw new ReflectionNameParseException(pos, "Invalid array modifier"); + } + } + break; + case ',': + // assembly qualified name, ignore everything up to the end/next ']' + while (pos < reflectionTypeName.Length && reflectionTypeName[pos] != ']') + pos++; + break; + default: + pos--; // reset pos to the character we couldn't read + if (reflectionTypeName[pos] == ']') + return reference; // return from a nested generic + else + throw new ReflectionNameParseException(pos, "Unexpected character: '" + reflectionTypeName[pos] + "'"); + } + } + return reference; + } + + static ITypeReference CreateGetClassTypeReference(string assemblyName, string typeName, int tpc) + { + IAssemblyReference assemblyReference; + if (assemblyName != null) { + assemblyReference = new DefaultAssemblyReference(assemblyName); + } else { + assemblyReference = null; + } + int pos = typeName.LastIndexOf('.'); + if (pos < 0) + return new GetClassTypeReference(assemblyReference, string.Empty, typeName, tpc); + else + return new GetClassTypeReference(assemblyReference, typeName.Substring(0, pos), typeName.Substring(pos + 1), tpc); + } + + static string SkipAheadAndReadAssemblyName(string reflectionTypeName, int pos) + { + int nestingLevel = 0; + while (pos < reflectionTypeName.Length) { + switch (reflectionTypeName[pos++]) { + case '[': + nestingLevel++; + break; + case ']': + if (nestingLevel == 0) + return null; + nestingLevel--; + break; + case ',': + if (nestingLevel == 0) { + // first skip the whitespace + while (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ' ') + pos++; + // everything up to the end/next ']' is the assembly name + int endPos = pos; + while (endPos < reflectionTypeName.Length && reflectionTypeName[endPos] != ']') + endPos++; + return reflectionTypeName.Substring(pos, endPos - pos); + } + break; + } + } + return null; + } + + static string ReadTypeName(string reflectionTypeName, ref int pos, out int tpc) + { + int startPos = pos; + // skip the simple name portion: + while (pos < reflectionTypeName.Length && !IsReflectionNameSpecialCharacter(reflectionTypeName[pos])) + pos++; + if (pos == startPos) + throw new ReflectionNameParseException(pos, "Expected type name"); + string typeName = reflectionTypeName.Substring(startPos, pos - startPos); + if (pos < reflectionTypeName.Length && reflectionTypeName[pos] == '`') { + pos++; + tpc = ReadTypeParameterCount(reflectionTypeName, ref pos); + } else { + tpc = 0; + } + return typeName; + } + + internal static int ReadTypeParameterCount(string reflectionTypeName, ref int pos) + { + int startPos = pos; + while (pos < reflectionTypeName.Length) { + char c = reflectionTypeName[pos]; + if (c < '0' || c > '9') + break; + pos++; + } + int tpc; + if (!int.TryParse(reflectionTypeName.Substring(startPos, pos - startPos), out tpc)) + throw new ReflectionNameParseException(pos, "Expected type parameter count"); + return tpc; + } + #endregion + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/ReflectionNameParseException.cs b/ICSharpCode.Decompiler/TypeSystem/ReflectionNameParseException.cs new file mode 100644 index 000000000..a54af9624 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/ReflectionNameParseException.cs @@ -0,0 +1,63 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Runtime.Serialization; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Represents an error while parsing a reflection name. + /// + [Serializable] + public class ReflectionNameParseException : Exception + { + int position; + + public int Position { + get { return position; } + } + + public ReflectionNameParseException(int position) + { + this.position = position; + } + + public ReflectionNameParseException(int position, string message) : base(message) + { + this.position = position; + } + + public ReflectionNameParseException(int position, string message, Exception innerException) : base(message, innerException) + { + this.position = position; + } + + // This constructor is needed for serialization. + protected ReflectionNameParseException(SerializationInfo info, StreamingContext context) : base(info, context) + { + position = info.GetInt32("position"); + } + + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("position", position); + } + } +} \ No newline at end of file diff --git a/ICSharpCode.Decompiler/TypeSystem/SimpleTypeResolveContext.cs b/ICSharpCode.Decompiler/TypeSystem/SimpleTypeResolveContext.cs new file mode 100644 index 000000000..8cda2952d --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/SimpleTypeResolveContext.cs @@ -0,0 +1,92 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Default ITypeResolveContext implementation. + /// + public class SimpleTypeResolveContext : ITypeResolveContext + { + readonly ICompilation compilation; + readonly IAssembly currentAssembly; + readonly ITypeDefinition currentTypeDefinition; + readonly IMember currentMember; + + public SimpleTypeResolveContext(ICompilation compilation) + { + if (compilation == null) + throw new ArgumentNullException("compilation"); + this.compilation = compilation; + } + + public SimpleTypeResolveContext(IAssembly assembly) + { + if (assembly == null) + throw new ArgumentNullException("assembly"); + this.compilation = assembly.Compilation; + this.currentAssembly = assembly; + } + + public SimpleTypeResolveContext(IEntity entity) + { + if (entity == null) + throw new ArgumentNullException("entity"); + this.compilation = entity.Compilation; + this.currentAssembly = entity.ParentAssembly; + this.currentTypeDefinition = (entity as ITypeDefinition) ?? entity.DeclaringTypeDefinition; + this.currentMember = entity as IMember; + } + + private SimpleTypeResolveContext(ICompilation compilation, IAssembly currentAssembly, ITypeDefinition currentTypeDefinition, IMember currentMember) + { + this.compilation = compilation; + this.currentAssembly = currentAssembly; + this.currentTypeDefinition = currentTypeDefinition; + this.currentMember = currentMember; + } + + public ICompilation Compilation { + get { return compilation; } + } + + public IAssembly CurrentAssembly { + get { return currentAssembly; } + } + + public ITypeDefinition CurrentTypeDefinition { + get { return currentTypeDefinition; } + } + + public IMember CurrentMember { + get { return currentMember; } + } + + public ITypeResolveContext WithCurrentTypeDefinition(ITypeDefinition typeDefinition) + { + return new SimpleTypeResolveContext(compilation, currentAssembly, typeDefinition, currentMember); + } + + public ITypeResolveContext WithCurrentMember(IMember member) + { + return new SimpleTypeResolveContext(compilation, currentAssembly, currentTypeDefinition, member); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/SpecialType.cs b/ICSharpCode.Decompiler/TypeSystem/SpecialType.cs new file mode 100644 index 000000000..1c67a7ec6 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/SpecialType.cs @@ -0,0 +1,106 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Implementation; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Contains static implementations of special types. + /// + [Serializable] + public sealed class SpecialType : AbstractType, ITypeReference + { + /// + /// Gets the type representing resolve errors. + /// + public readonly static SpecialType UnknownType = new SpecialType(TypeKind.Unknown, "?", isReferenceType: null); + + /// + /// The null type is used as type of the null literal. It is a reference type without any members; and it is a subtype of all reference types. + /// + public readonly static SpecialType NullType = new SpecialType(TypeKind.Null, "null", isReferenceType: true); + + /// + /// Type representing the C# 'dynamic' type. + /// + public readonly static SpecialType Dynamic = new SpecialType(TypeKind.Dynamic, "dynamic", isReferenceType: true); + + /// + /// Type representing the result of the C# '__arglist()' expression. + /// + public readonly static SpecialType ArgList = new SpecialType(TypeKind.ArgList, "__arglist", isReferenceType: null); + + /// + /// A type used for unbound type arguments in partially parameterized types. + /// + /// + public readonly static SpecialType UnboundTypeArgument = new SpecialType(TypeKind.UnboundTypeArgument, "", isReferenceType: null); + + readonly TypeKind kind; + readonly string name; + readonly bool? isReferenceType; + + private SpecialType(TypeKind kind, string name, bool? isReferenceType) + { + this.kind = kind; + this.name = name; + this.isReferenceType = isReferenceType; + } + + public override ITypeReference ToTypeReference() + { + return this; + } + + public override string Name { + get { return name; } + } + + public override TypeKind Kind { + get { return kind; } + } + + public override bool? IsReferenceType { + get { return isReferenceType; } + } + + IType ITypeReference.Resolve(ITypeResolveContext context) + { + if (context == null) + throw new ArgumentNullException("context"); + return this; + } + + #pragma warning disable 809 + [Obsolete("Please compare special types using the kind property instead.")] + public override bool Equals(IType other) + { + // We consider a special types equal when they have equal types. + // However, an unknown type with additional information is not considered to be equal to the SpecialType with TypeKind.Unknown. + return other is SpecialType && other.Kind == kind; + } + + public override int GetHashCode() + { + return 81625621 ^ (int)kind; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/TaskType.cs b/ICSharpCode.Decompiler/TypeSystem/TaskType.cs new file mode 100644 index 000000000..58e958bb6 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/TaskType.cs @@ -0,0 +1,78 @@ +// Copyright (c) 2010-2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Helper class for dealing with System.Threading.Tasks.Task. + /// + public static class TaskType + { + /// + /// Gets the T in Task<T>. + /// Returns void for non-generic Task. + /// Any other type is returned unmodified. + /// + public static IType UnpackTask(ICompilation compilation, IType type) + { + if (!IsTask(type)) + return type; + if (type.TypeParameterCount == 0) + return compilation.FindType(KnownTypeCode.Void); + else + return type.TypeArguments[0]; + } + + /// + /// Gets whether the specified type is Task or Task<T>. + /// + public static bool IsTask(IType type) + { + ITypeDefinition def = type.GetDefinition(); + if (def != null) { + if (def.KnownTypeCode == KnownTypeCode.Task) + return true; + if (def.KnownTypeCode == KnownTypeCode.TaskOfT) + return type is ParameterizedType; + } + return false; + } + + /// + /// Creates a task type. + /// + public static IType Create(ICompilation compilation, IType elementType) + { + if (compilation == null) + throw new ArgumentNullException("compilation"); + if (elementType == null) + throw new ArgumentNullException("elementType"); + + if (elementType.Kind == TypeKind.Void) + return compilation.FindType(KnownTypeCode.Task); + IType taskType = compilation.FindType(KnownTypeCode.TaskOfT); + ITypeDefinition taskTypeDef = taskType.GetDefinition(); + if (taskTypeDef != null) + return new ParameterizedType(taskTypeDef, new [] { elementType }); + else + return taskType; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/TopLevelTypeName.cs b/ICSharpCode.Decompiler/TypeSystem/TopLevelTypeName.cs new file mode 100644 index 000000000..fb13eea6c --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/TopLevelTypeName.cs @@ -0,0 +1,144 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Text; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Holds the name of a top-level type. + /// This struct cannot refer to nested classes. + /// + [Serializable] + public struct TopLevelTypeName : IEquatable + { + readonly string namespaceName; + readonly string name; + readonly int typeParameterCount; + + public TopLevelTypeName(string namespaceName, string name, int typeParameterCount = 0) + { + if (namespaceName == null) + throw new ArgumentNullException("namespaceName"); + if (name == null) + throw new ArgumentNullException("name"); + this.namespaceName = namespaceName; + this.name = name; + this.typeParameterCount = typeParameterCount; + } + + public TopLevelTypeName(string reflectionName) + { + int pos = reflectionName.LastIndexOf('.'); + if (pos < 0) { + namespaceName = string.Empty; + name = reflectionName; + } else { + namespaceName = reflectionName.Substring(0, pos); + name = reflectionName.Substring(pos + 1); + } + name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(name, out typeParameterCount); + } + + public string Namespace { + get { return namespaceName; } + } + + public string Name { + get { return name; } + } + + public int TypeParameterCount { + get { return typeParameterCount; } + } + + public string ReflectionName { + get { + StringBuilder b = new StringBuilder(); + if (!string.IsNullOrEmpty(namespaceName)) { + b.Append(namespaceName); + b.Append('.'); + } + b.Append(name); + if (typeParameterCount > 0) { + b.Append('`'); + b.Append(typeParameterCount); + } + return b.ToString(); + } + } + + public override string ToString() + { + return this.ReflectionName; + } + + public override bool Equals(object obj) + { + return (obj is TopLevelTypeName) && Equals((TopLevelTypeName)obj); + } + + public bool Equals(TopLevelTypeName other) + { + return this.namespaceName == other.namespaceName && this.name == other.name && this.typeParameterCount == other.typeParameterCount; + } + + public override int GetHashCode() + { + return (name != null ? name.GetHashCode() : 0) ^ (namespaceName != null ? namespaceName.GetHashCode() : 0) ^ typeParameterCount; + } + + public static bool operator ==(TopLevelTypeName lhs, TopLevelTypeName rhs) + { + return lhs.Equals(rhs); + } + + public static bool operator !=(TopLevelTypeName lhs, TopLevelTypeName rhs) + { + return !lhs.Equals(rhs); + } + } + + [Serializable] + public sealed class TopLevelTypeNameComparer : IEqualityComparer + { + public static readonly TopLevelTypeNameComparer Ordinal = new TopLevelTypeNameComparer(StringComparer.Ordinal); + public static readonly TopLevelTypeNameComparer OrdinalIgnoreCase = new TopLevelTypeNameComparer(StringComparer.OrdinalIgnoreCase); + + public readonly StringComparer NameComparer; + + public TopLevelTypeNameComparer(StringComparer nameComparer) + { + this.NameComparer = nameComparer; + } + + public bool Equals(TopLevelTypeName x, TopLevelTypeName y) + { + return x.TypeParameterCount == y.TypeParameterCount + && NameComparer.Equals(x.Name, y.Name) + && NameComparer.Equals(x.Namespace, y.Namespace); + } + + public int GetHashCode(TopLevelTypeName obj) + { + return NameComparer.GetHashCode(obj.Name) ^ NameComparer.GetHashCode(obj.Namespace) ^ obj.TypeParameterCount; + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/TypeKind.cs b/ICSharpCode.Decompiler/TypeSystem/TypeKind.cs new file mode 100644 index 000000000..dd5d9b066 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/TypeKind.cs @@ -0,0 +1,86 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// . + /// + public enum TypeKind : byte + { + /// Language-specific type that is not part of NRefactory.TypeSystem itself. + Other, + + /// A or that is a class. + Class, + /// A or that is an interface. + Interface, + /// A or that is a struct. + Struct, + /// A or that is a delegate. + /// System.Delegate itself is TypeKind.Class + Delegate, + /// A that is an enum. + /// System.Enum itself is TypeKind.Class + Enum, + /// A that is a module (VB). + Module, + + /// The System.Void type. + /// + Void, + + /// + Unknown, + /// The type of the null literal. + /// + Null, + /// Type representing the C# 'dynamic' type. + /// + Dynamic, + /// Represents missing type arguments in partially parameterized types. + /// + /// + UnboundTypeArgument, + + /// The type is a type parameter. + /// + TypeParameter, + + /// An array type + /// + Array, + /// A pointer type + /// + Pointer, + /// A managed reference type + /// + ByReference, + /// An anonymous type + /// + Anonymous, + + /// Intersection of several types + /// + Intersection, + /// + ArgList, + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/TypeParameterSubstitution.cs b/ICSharpCode.Decompiler/TypeSystem/TypeParameterSubstitution.cs new file mode 100644 index 000000000..28b4abb37 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/TypeParameterSubstitution.cs @@ -0,0 +1,193 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Text; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Substitutes class and method type parameters. + /// + public class TypeParameterSubstitution : TypeVisitor + { + /// + /// The identity function. + /// + public static readonly TypeParameterSubstitution Identity = new TypeParameterSubstitution(null, null); + + readonly IList classTypeArguments; + readonly IList methodTypeArguments; + + /// + /// Creates a new type parameter substitution. + /// + /// + /// The type arguments to substitute for class type parameters. + /// Pass null to keep class type parameters unmodified. + /// + /// + /// The type arguments to substitute for method type parameters. + /// Pass null to keep method type parameters unmodified. + /// + public TypeParameterSubstitution(IList classTypeArguments, IList methodTypeArguments) + { + this.classTypeArguments = classTypeArguments; + this.methodTypeArguments = methodTypeArguments; + } + + /// + /// Gets the list of class type arguments. + /// Returns null if this substitution keeps class type parameters unmodified. + /// + public IList ClassTypeArguments { + get { return classTypeArguments; } + } + + /// + /// Gets the list of method type arguments. + /// Returns null if this substitution keeps method type parameters unmodified. + /// + public IList MethodTypeArguments { + get { return methodTypeArguments; } + } + + #region Compose + /// + /// Computes a single TypeParameterSubstitution so that for all types t: + /// t.AcceptVisitor(Compose(g, f)) equals t.AcceptVisitor(f).AcceptVisitor(g) + /// + /// If you consider type parameter substitution to be a function, this is function composition. + public static TypeParameterSubstitution Compose(TypeParameterSubstitution g, TypeParameterSubstitution f) + { + if (g == null) + return f; + if (f == null || (f.classTypeArguments == null && f.methodTypeArguments == null)) + return g; + // The composition is a copy of 'f', with 'g' applied on the array elements. + // If 'f' has a null list (keeps type parameters unmodified), we have to treat it as + // the identity function, and thus use the list from 'g'. + var classTypeArguments = f.classTypeArguments != null ? GetComposedTypeArguments(f.classTypeArguments, g) : g.classTypeArguments; + var methodTypeArguments = f.methodTypeArguments != null ? GetComposedTypeArguments(f.methodTypeArguments, g) : g.methodTypeArguments; + return new TypeParameterSubstitution(classTypeArguments, methodTypeArguments); + } + + static IList GetComposedTypeArguments(IList input, TypeParameterSubstitution substitution) + { + IType[] result = new IType[input.Count]; + for (int i = 0; i < result.Length; i++) { + result[i] = input[i].AcceptVisitor(substitution); + } + return result; + } + #endregion + + #region Equals and GetHashCode implementation + public override bool Equals(object obj) + { + TypeParameterSubstitution other = obj as TypeParameterSubstitution; + if (other == null) + return false; + return TypeListEquals(classTypeArguments, other.classTypeArguments) + && TypeListEquals(methodTypeArguments, other.methodTypeArguments); + } + + public override int GetHashCode() + { + unchecked { + return 1124131 * TypeListHashCode(classTypeArguments) + 1821779 * TypeListHashCode(methodTypeArguments); + } + } + + static bool TypeListEquals(IList a, IList b) + { + if (a == b) + return true; + if (a == null || b == null) + return false; + if (a.Count != b.Count) + return false; + for (int i = 0; i < a.Count; i++) { + if (!a[i].Equals(b[i])) + return false; + } + return true; + } + + static int TypeListHashCode(IList obj) + { + if (obj == null) + return 0; + unchecked { + int hashCode = 1; + foreach (var element in obj) { + hashCode *= 27; + hashCode += element.GetHashCode(); + } + return hashCode; + } + } + #endregion + + public override IType VisitTypeParameter(ITypeParameter type) + { + int index = type.Index; + if (classTypeArguments != null && type.OwnerType == SymbolKind.TypeDefinition) { + if (index >= 0 && index < classTypeArguments.Count) + return classTypeArguments[index]; + else + return SpecialType.UnknownType; + } else if (methodTypeArguments != null && type.OwnerType == SymbolKind.Method) { + if (index >= 0 && index < methodTypeArguments.Count) + return methodTypeArguments[index]; + else + return SpecialType.UnknownType; + } else { + return base.VisitTypeParameter(type); + } + } + + public override string ToString() + { + StringBuilder b = new StringBuilder(); + b.Append('['); + bool first = true; + if (classTypeArguments != null) { + for (int i = 0; i < classTypeArguments.Count; i++) { + if (first) first = false; else b.Append(", "); + b.Append('`'); + b.Append(i); + b.Append(" -> "); + b.Append(classTypeArguments[i].ReflectionName); + } + } + if (methodTypeArguments != null) { + for (int i = 0; i < methodTypeArguments.Count; i++) { + if (first) first = false; else b.Append(", "); + b.Append("``"); + b.Append(i); + b.Append(" -> "); + b.Append(methodTypeArguments[i].ReflectionName); + } + } + b.Append(']'); + return b.ToString(); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs b/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs new file mode 100644 index 000000000..fd818302e --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs @@ -0,0 +1,790 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; +using ICSharpCode.NRefactory.Semantics; +using ICSharpCode.NRefactory.TypeSystem.Implementation; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Contains extension methods for the type system. + /// + public static class TypeSystemExtensions + { + #region GetAllBaseTypes + /// + /// Gets all base types. + /// + /// This is the reflexive and transitive closure of . + /// Note that this method does not return all supertypes - doing so is impossible due to contravariance + /// (and undesirable for covariance as the list could become very large). + /// + /// The output is ordered so that base types occur before derived types. + /// + public static IEnumerable GetAllBaseTypes(this IType type) + { + if (type == null) + throw new ArgumentNullException("type"); + BaseTypeCollector collector = new BaseTypeCollector(); + collector.CollectBaseTypes(type); + return collector; + } + + /// + /// Gets all non-interface base types. + /// + /// + /// When is an interface, this method will also return base interfaces (return same output as GetAllBaseTypes()). + /// + /// The output is ordered so that base types occur before derived types. + /// + public static IEnumerable GetNonInterfaceBaseTypes(this IType type) + { + if (type == null) + throw new ArgumentNullException("type"); + BaseTypeCollector collector = new BaseTypeCollector(); + collector.SkipImplementedInterfaces = true; + collector.CollectBaseTypes(type); + return collector; + } + #endregion + + #region GetAllBaseTypeDefinitions + /// + /// Gets all base type definitions. + /// The output is ordered so that base types occur before derived types. + /// + /// + /// This is equivalent to type.GetAllBaseTypes().Select(t => t.GetDefinition()).Where(d => d != null).Distinct(). + /// + public static IEnumerable GetAllBaseTypeDefinitions(this IType type) + { + if (type == null) + throw new ArgumentNullException("type"); + + return type.GetAllBaseTypes().Select(t => t.GetDefinition()).Where(d => d != null).Distinct(); + } + + /// + /// Gets whether this type definition is derived from the base type definition. + /// + public static bool IsDerivedFrom(this ITypeDefinition type, ITypeDefinition baseType) + { + if (type == null) + throw new ArgumentNullException("type"); + if (baseType == null) + return false; + if (type.Compilation != baseType.Compilation) { + throw new InvalidOperationException("Both arguments to IsDerivedFrom() must be from the same compilation."); + } + return type.GetAllBaseTypeDefinitions().Contains(baseType); + } + + /// + /// Gets whether this type definition is derived from a given known type. + /// + public static bool IsDerivedFrom(this ITypeDefinition type, KnownTypeCode baseType) + { + if (type == null) + throw new ArgumentNullException("type"); + if (baseType == KnownTypeCode.None) + return false; + return IsDerivedFrom(type, type.Compilation.FindType(baseType).GetDefinition()); + } + #endregion + + #region IsOpen / IsUnbound / IsKnownType + sealed class TypeClassificationVisitor : TypeVisitor + { + internal bool isOpen; + internal IEntity typeParameterOwner; + int typeParameterOwnerNestingLevel; + + public override IType VisitTypeParameter(ITypeParameter type) + { + isOpen = true; + // If both classes and methods, or different classes (nested types) + // are involved, find the most specific one + int newNestingLevel = GetNestingLevel(type.Owner); + if (newNestingLevel > typeParameterOwnerNestingLevel) { + typeParameterOwner = type.Owner; + typeParameterOwnerNestingLevel = newNestingLevel; + } + return base.VisitTypeParameter(type); + } + + static int GetNestingLevel(IEntity entity) + { + int level = 0; + while (entity != null) { + level++; + entity = entity.DeclaringTypeDefinition; + } + return level; + } + } + + /// + /// Gets whether the type is an open type (contains type parameters). + /// + /// + /// + /// class X<T> { + /// List<T> open; + /// X<X<T[]>> open; + /// X<string> closed; + /// int closed; + /// } + /// + /// + public static bool IsOpen(this IType type) + { + if (type == null) + throw new ArgumentNullException("type"); + TypeClassificationVisitor v = new TypeClassificationVisitor(); + type.AcceptVisitor(v); + return v.isOpen; + } + + /// + /// Gets the entity that owns the type parameters occurring in the specified type. + /// If both class and method type parameters are present, the method is returned. + /// Returns null if the specified type is closed. + /// + /// + static IEntity GetTypeParameterOwner(IType type) + { + if (type == null) + throw new ArgumentNullException("type"); + TypeClassificationVisitor v = new TypeClassificationVisitor(); + type.AcceptVisitor(v); + return v.typeParameterOwner; + } + + /// + /// Gets whether the type is unbound (is a generic type, but no type arguments were provided). + /// + /// + /// In "typeof(List<Dictionary<,>>)", only the Dictionary is unbound, the List is considered + /// bound despite containing an unbound type. + /// This method returns false for partially parameterized types (Dictionary<string, >). + /// + public static bool IsUnbound(this IType type) + { + if (type == null) + throw new ArgumentNullException("type"); + return type is ITypeDefinition && type.TypeParameterCount > 0; + } + + /// + /// Gets whether the type is the specified known type. + /// For generic known types, this returns true any parameterization of the type (and also for the definition itself). + /// + public static bool IsKnownType(this IType type, KnownTypeCode knownType) + { + var def = type.GetDefinition(); + return def != null && def.KnownTypeCode == knownType; + } + #endregion + + #region Import + /// + /// Imports a symbol from another compilation. + /// + public static ISymbol Import(this ICompilation compilation, ISymbol symbol) + { + if (compilation == null) + throw new ArgumentNullException("compilation"); + if (symbol == null) + return null; + switch (symbol.SymbolKind) { + case SymbolKind.TypeParameter: + return (ITypeParameter)Import(compilation, (IType)symbol); + case SymbolKind.Variable: + IVariable v = (IVariable)symbol; + return new DefaultVariable( + Import(compilation, v.Type), + v.Name, v.Region, v.IsConst, v.ConstantValue + ); + case SymbolKind.Parameter: + IParameter p = (IParameter)symbol; + if (p.Owner != null) { + int index = p.Owner.Parameters.IndexOf(p); + var owner = (IParameterizedMember)Import(compilation, p.Owner); + if (owner == null || index < 0 || index >= owner.Parameters.Count) + return null; + return owner.Parameters[index]; + } else { + return new DefaultParameter( + Import(compilation, p.Type), + p.Name, null, p.Region, + null, p.IsRef, p.IsOut, p.IsParams + ); + } + case SymbolKind.Namespace: + return Import(compilation, (INamespace)symbol); + default: + if (symbol is IEntity) + return Import(compilation, (IEntity)symbol); + throw new NotSupportedException("Unsupported symbol kind: " + symbol.SymbolKind); + } + } + + /// + /// Imports a type from another compilation. + /// + public static IType Import(this ICompilation compilation, IType type) + { + if (compilation == null) + throw new ArgumentNullException("compilation"); + if (type == null) + return null; + var compilationProvider = type as ICompilationProvider; + if (compilationProvider != null && compilationProvider.Compilation == compilation) + return type; + IEntity typeParameterOwner = GetTypeParameterOwner(type); + IEntity importedTypeParameterOwner = compilation.Import(typeParameterOwner); + if (importedTypeParameterOwner != null) { + return type.ToTypeReference().Resolve(new SimpleTypeResolveContext(importedTypeParameterOwner)); + } else { + return type.ToTypeReference().Resolve(compilation.TypeResolveContext); + } + } + + /// + /// Imports a type from another compilation. + /// + public static ITypeDefinition Import(this ICompilation compilation, ITypeDefinition typeDefinition) + { + if (compilation == null) + throw new ArgumentNullException("compilation"); + if (typeDefinition == null) + return null; + if (typeDefinition.Compilation == compilation) + return typeDefinition; + return typeDefinition.ToTypeReference().Resolve(compilation.TypeResolveContext).GetDefinition(); + } + + /// + /// Imports an entity from another compilation. + /// + public static IEntity Import(this ICompilation compilation, IEntity entity) + { + if (compilation == null) + throw new ArgumentNullException("compilation"); + if (entity == null) + return null; + if (entity.Compilation == compilation) + return entity; + if (entity is IMember) + return ((IMember)entity).ToReference().Resolve(compilation.TypeResolveContext); + else if (entity is ITypeDefinition) + return ((ITypeDefinition)entity).ToTypeReference().Resolve(compilation.TypeResolveContext).GetDefinition(); + else + throw new NotSupportedException("Unknown entity type"); + } + + /// + /// Imports a member from another compilation. + /// + public static IMember Import(this ICompilation compilation, IMember member) + { + if (compilation == null) + throw new ArgumentNullException("compilation"); + if (member == null) + return null; + if (member.Compilation == compilation) + return member; + return member.ToReference().Resolve(compilation.TypeResolveContext); + } + + /// + /// Imports a member from another compilation. + /// + public static IMethod Import(this ICompilation compilation, IMethod method) + { + return (IMethod)compilation.Import((IMember)method); + } + + /// + /// Imports a member from another compilation. + /// + public static IField Import(this ICompilation compilation, IField field) + { + return (IField)compilation.Import((IMember)field); + } + + /// + /// Imports a member from another compilation. + /// + public static IEvent Import(this ICompilation compilation, IEvent ev) + { + return (IEvent)compilation.Import((IMember)ev); + } + + /// + /// Imports a member from another compilation. + /// + public static IProperty Import(this ICompilation compilation, IProperty property) + { + return (IProperty)compilation.Import((IMember)property); + } + + /// + /// Imports a namespace from another compilation. + /// + /// + /// This method may return null if the namespace does not exist in the target compilation. + /// + public static INamespace Import(this ICompilation compilation, INamespace ns) + { + if (compilation == null) + throw new ArgumentNullException("compilation"); + if (ns == null) + return null; + if (ns.ParentNamespace == null) { + // root namespace + return compilation.GetNamespaceForExternAlias(ns.ExternAlias); + } else { + INamespace parent = Import(compilation, ns.ParentNamespace); + if (parent != null) + return parent.GetChildNamespace(ns.Name); + else + return null; + } + } + #endregion + + #region GetDelegateInvokeMethod + /// + /// Gets the invoke method for a delegate type. + /// + /// + /// Returns null if the type is not a delegate type; or if the invoke method could not be found. + /// + public static IMethod GetDelegateInvokeMethod(this IType type) + { + if (type == null) + throw new ArgumentNullException("type"); + if (type.Kind == TypeKind.Delegate) + return type.GetMethods(m => m.Name == "Invoke", GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault(); + else + return null; + } + #endregion + + #region GetType/Member + /// + /// Gets all unresolved type definitions from the file. + /// For partial classes, each part is returned. + /// + public static IEnumerable GetAllTypeDefinitions (this IUnresolvedFile file) + { + return TreeTraversal.PreOrder(file.TopLevelTypeDefinitions, t => t.NestedTypes); + } + + /// + /// Gets all unresolved type definitions from the assembly. + /// For partial classes, each part is returned. + /// + public static IEnumerable GetAllTypeDefinitions (this IUnresolvedAssembly assembly) + { + return TreeTraversal.PreOrder(assembly.TopLevelTypeDefinitions, t => t.NestedTypes); + } + + public static IEnumerable GetAllTypeDefinitions (this IAssembly assembly) + { + return TreeTraversal.PreOrder(assembly.TopLevelTypeDefinitions, t => t.NestedTypes); + } + + /// + /// Gets all type definitions in the compilation. + /// This may include types from referenced assemblies that are not accessible in the main assembly. + /// + public static IEnumerable GetAllTypeDefinitions (this ICompilation compilation) + { + return compilation.Assemblies.SelectMany(a => a.GetAllTypeDefinitions()); + } + + /// + /// Gets all top level type definitions in the compilation. + /// This may include types from referenced assemblies that are not accessible in the main assembly. + /// + public static IEnumerable GetTopLevelTypeDefinitons (this ICompilation compilation) + { + return compilation.Assemblies.SelectMany(a => a.TopLevelTypeDefinitions); + } + + /// + /// Gets the type (potentially a nested type) defined at the specified location. + /// Returns null if no type is defined at that location. + /// + public static IUnresolvedTypeDefinition GetInnermostTypeDefinition (this IUnresolvedFile file, int line, int column) + { + return file.GetInnermostTypeDefinition (new TextLocation (line, column)); + } + + /// + /// Gets the member defined at the specified location. + /// Returns null if no member is defined at that location. + /// + public static IUnresolvedMember GetMember (this IUnresolvedFile file, int line, int column) + { + return file.GetMember (new TextLocation (line, column)); + } + #endregion + + #region Resolve on collections + public static IList CreateResolvedAttributes(this IList attributes, ITypeResolveContext context) + { + if (attributes == null) + throw new ArgumentNullException("attributes"); + if (attributes.Count == 0) + return EmptyList.Instance; + else + return new ProjectedList(context, attributes, (c, a) => a.CreateResolvedAttribute(c)); + } + + public static IList CreateResolvedTypeParameters(this IList typeParameters, ITypeResolveContext context) + { + if (typeParameters == null) + throw new ArgumentNullException("typeParameters"); + if (typeParameters.Count == 0) + return EmptyList.Instance; + else + return new ProjectedList(context, typeParameters, (c, a) => a.CreateResolvedTypeParameter(c)); + } + + public static IList CreateResolvedParameters(this IList parameters, ITypeResolveContext context) + { + if (parameters == null) + throw new ArgumentNullException("parameters"); + if (parameters.Count == 0) + return EmptyList.Instance; + else + return new ProjectedList(context, parameters, (c, a) => a.CreateResolvedParameter(c)); + } + + public static IList Resolve(this IList typeReferences, ITypeResolveContext context) + { + if (typeReferences == null) + throw new ArgumentNullException("typeReferences"); + if (typeReferences.Count == 0) + return EmptyList.Instance; + else + return new ProjectedList(context, typeReferences, (c, t) => t.Resolve(c)); + } + + // There is intentionally no Resolve() overload for IList: the resulting IList would + // contains nulls when there are resolve errors. + + public static IList Resolve(this IList constantValues, ITypeResolveContext context) + { + if (constantValues == null) + throw new ArgumentNullException("constantValues"); + if (constantValues.Count == 0) + return EmptyList.Instance; + else + return new ProjectedList(context, constantValues, (c, t) => t.Resolve(c)); + } + #endregion + + #region GetSubTypeDefinitions + public static IEnumerable GetSubTypeDefinitions (this IType baseType) + { + if (baseType == null) + throw new ArgumentNullException ("baseType"); + var def = baseType.GetDefinition (); + if (def == null) + return Enumerable.Empty (); + return def.GetSubTypeDefinitions (); + } + + /// + /// Gets all sub type definitions defined in a context. + /// + public static IEnumerable GetSubTypeDefinitions (this ITypeDefinition baseType) + { + if (baseType == null) + throw new ArgumentNullException ("baseType"); + foreach (var contextType in baseType.Compilation.GetAllTypeDefinitions ()) { + if (contextType.IsDerivedFrom (baseType)) + yield return contextType; + } + } + #endregion + + #region IAssembly.GetTypeDefinition() + /// + /// Retrieves the specified type in this compilation. + /// Returns an if the type cannot be found in this compilation. + /// + /// + /// There can be multiple types with the same full name in a compilation, as a + /// full type name is only unique per assembly. + /// If there are multiple possible matches, this method will return just one of them. + /// When possible, use instead to + /// retrieve a type from a specific assembly. + /// + public static IType FindType(this ICompilation compilation, FullTypeName fullTypeName) + { + if (compilation == null) + throw new ArgumentNullException("compilation"); + foreach (IAssembly asm in compilation.Assemblies) { + ITypeDefinition def = asm.GetTypeDefinition(fullTypeName); + if (def != null) + return def; + } + return new UnknownType(fullTypeName); + } + + /// + /// Gets the type definition for the specified unresolved type. + /// Returns null if the unresolved type does not belong to this assembly. + /// + public static ITypeDefinition GetTypeDefinition(this IAssembly assembly, FullTypeName fullTypeName) + { + if (assembly == null) + throw new ArgumentNullException("assembly"); + TopLevelTypeName topLevelTypeName = fullTypeName.TopLevelTypeName; + ITypeDefinition typeDef = assembly.GetTypeDefinition(topLevelTypeName); + if (typeDef == null) + return null; + int typeParameterCount = topLevelTypeName.TypeParameterCount; + for (int i = 0; i < fullTypeName.NestingLevel; i++) { + string name = fullTypeName.GetNestedTypeName(i); + typeParameterCount += fullTypeName.GetNestedTypeAdditionalTypeParameterCount(i); + typeDef = FindNestedType(typeDef, name, typeParameterCount); + if (typeDef == null) + break; + } + return typeDef; + } + + static ITypeDefinition FindNestedType(ITypeDefinition typeDef, string name, int typeParameterCount) + { + foreach (var nestedType in typeDef.NestedTypes) { + if (nestedType.Name == name && nestedType.TypeParameterCount == typeParameterCount) + return nestedType; + } + return null; + } + #endregion + + #region ITypeReference.Resolve(ICompilation) + + /// + /// Resolves a type reference in the compilation's main type resolve context. + /// Some type references require a more specific type resolve context and will not resolve using this method. + /// + /// + /// Returns the resolved type. + /// In case of an error, returns . + /// Never returns null. + /// + public static IType Resolve (this ITypeReference reference, ICompilation compilation) + { + if (reference == null) + throw new ArgumentNullException ("reference"); + if (compilation == null) + throw new ArgumentNullException ("compilation"); + return reference.Resolve (compilation.TypeResolveContext); + } + #endregion + + #region ITypeDefinition.GetAttribute + /// + /// Gets the attribute of the specified attribute type (or derived attribute types). + /// + /// The entity on which the attributes are declared. + /// The attribute type to look for. + /// + /// Specifies whether attributes inherited from base classes and base members (if the given in an override) + /// should be returned. The default is true. + /// + /// + /// Returns the attribute that was found; or null if none was found. + /// If inherit is true, an from the entity itself will be returned if possible; + /// and the base entity will only be searched if none exists. + /// + public static IAttribute GetAttribute(this IEntity entity, IType attributeType, bool inherit = true) + { + return GetAttributes(entity, attributeType, inherit).FirstOrDefault(); + } + + /// + /// Gets the attributes of the specified attribute type (or derived attribute types). + /// + /// The entity on which the attributes are declared. + /// The attribute type to look for. + /// + /// Specifies whether attributes inherited from base classes and base members (if the given in an override) + /// should be returned. The default is true. + /// + /// + /// Returns the list of attributes that were found. + /// If inherit is true, attributes from the entity itself are returned first; followed by attributes inherited from the base entity. + /// + public static IEnumerable GetAttributes(this IEntity entity, IType attributeType, bool inherit = true) + { + if (entity == null) + throw new ArgumentNullException("entity"); + if (attributeType == null) + throw new ArgumentNullException("attributeType"); + return GetAttributes(entity, attributeType.Equals, inherit); + } + + /// + /// Gets the attribute of the specified attribute type (or derived attribute types). + /// + /// The entity on which the attributes are declared. + /// The attribute type to look for. + /// + /// Specifies whether attributes inherited from base classes and base members (if the given in an override) + /// should be returned. The default is true. + /// + /// + /// Returns the attribute that was found; or null if none was found. + /// If inherit is true, an from the entity itself will be returned if possible; + /// and the base entity will only be searched if none exists. + /// + public static IAttribute GetAttribute(this IEntity entity, FullTypeName attributeType, bool inherit = true) + { + return GetAttributes(entity, attributeType, inherit).FirstOrDefault(); + } + + /// + /// Gets the attributes of the specified attribute type (or derived attribute types). + /// + /// The entity on which the attributes are declared. + /// The attribute type to look for. + /// + /// Specifies whether attributes inherited from base classes and base members (if the given in an override) + /// should be returned. The default is true. + /// + /// + /// Returns the list of attributes that were found. + /// If inherit is true, attributes from the entity itself are returned first; followed by attributes inherited from the base entity. + /// + public static IEnumerable GetAttributes(this IEntity entity, FullTypeName attributeType, bool inherit = true) + { + if (entity == null) + throw new ArgumentNullException("entity"); + return GetAttributes(entity, attrType => { + ITypeDefinition typeDef = attrType.GetDefinition(); + return typeDef != null && typeDef.FullTypeName == attributeType; + }, inherit); + } + + /// + /// Gets the attribute of the specified attribute type (or derived attribute types). + /// + /// The entity on which the attributes are declared. + /// + /// Specifies whether attributes inherited from base classes and base members (if the given in an override) + /// should be returned. The default is true. + /// + /// + /// Returns the attribute that was found; or null if none was found. + /// If inherit is true, an from the entity itself will be returned if possible; + /// and the base entity will only be searched if none exists. + /// + public static IEnumerable GetAttributes(this IEntity entity, bool inherit = true) + { + if (entity == null) + throw new ArgumentNullException ("entity"); + return GetAttributes(entity, a => true, inherit); + } + + static IEnumerable GetAttributes(IEntity entity, Predicate attributeTypePredicate, bool inherit) + { + if (!inherit) { + foreach (var attr in entity.Attributes) { + if (attributeTypePredicate(attr.AttributeType)) + yield return attr; + } + yield break; + } + ITypeDefinition typeDef = entity as ITypeDefinition; + if (typeDef != null) { + foreach (var baseType in typeDef.GetNonInterfaceBaseTypes().Reverse()) { + ITypeDefinition baseTypeDef = baseType.GetDefinition(); + if (baseTypeDef == null) + continue; + foreach (var attr in baseTypeDef.Attributes) { + if (attributeTypePredicate(attr.AttributeType)) + yield return attr; + } + } + yield break; + } + IMember member = entity as IMember; + if (member != null) { + HashSet visitedMembers = new HashSet(); + do { + member = member.MemberDefinition; // it's sufficient to look at the definitions + if (!visitedMembers.Add(member)) { + // abort if we seem to be in an infinite loop (cyclic inheritance) + break; + } + foreach (var attr in member.Attributes) { + if (attributeTypePredicate(attr.AttributeType)) + yield return attr; + } + } while (member.IsOverride && (member = InheritanceHelper.GetBaseMember(member)) != null); + yield break; + } + throw new NotSupportedException("Unknown entity type"); + } + #endregion + + #region IAssembly.GetTypeDefinition(string,string,int) + /// + /// Gets the type definition for a top-level type. + /// + /// This method uses ordinal name comparison, not the compilation's name comparer. + public static ITypeDefinition GetTypeDefinition(this IAssembly assembly, string namespaceName, string name, int typeParameterCount = 0) + { + if (assembly == null) + throw new ArgumentNullException ("assembly"); + return assembly.GetTypeDefinition (new TopLevelTypeName (namespaceName, name, typeParameterCount)); + } + #endregion + + #region ResolveResult + public static ISymbol GetSymbol(this ResolveResult rr) + { + if (rr is LocalResolveResult) { + return ((LocalResolveResult)rr).Variable; + } else if (rr is MemberResolveResult) { + return ((MemberResolveResult)rr).Member; + } else if (rr is TypeResolveResult) { + return ((TypeResolveResult)rr).Type.GetDefinition(); + } else if (rr is ConversionResolveResult) { + return ((ConversionResolveResult)rr).Input.GetSymbol(); + } + + return null; + } + #endregion + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/TypeVisitor.cs b/ICSharpCode.Decompiler/TypeSystem/TypeVisitor.cs new file mode 100644 index 000000000..7c6cc1631 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/TypeVisitor.cs @@ -0,0 +1,63 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Base class for the visitor pattern on . + /// + public abstract class TypeVisitor + { + public virtual IType VisitTypeDefinition(ITypeDefinition type) + { + return type.VisitChildren(this); + } + + public virtual IType VisitTypeParameter(ITypeParameter type) + { + return type.VisitChildren(this); + } + + public virtual IType VisitParameterizedType(ParameterizedType type) + { + return type.VisitChildren(this); + } + + public virtual IType VisitArrayType(ArrayType type) + { + return type.VisitChildren(this); + } + + public virtual IType VisitPointerType(PointerType type) + { + return type.VisitChildren(this); + } + + public virtual IType VisitByReferenceType(ByReferenceType type) + { + return type.VisitChildren(this); + } + + public virtual IType VisitOtherType(IType type) + { + return type.VisitChildren(this); + } + } +} diff --git a/ICSharpCode.Decompiler/Util/7BitEncodedInts.cs b/ICSharpCode.Decompiler/Util/7BitEncodedInts.cs new file mode 100644 index 000000000..01f507293 --- /dev/null +++ b/ICSharpCode.Decompiler/Util/7BitEncodedInts.cs @@ -0,0 +1,123 @@ +// Copyright (c) 2011 Daniel Grunwald +// +// 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.IO; + +namespace ICSharpCode.NRefactory.Utils +{ + /// + /// A binary reader that can read the output of BinaryWriterWith7BitEncodedInts. + /// + public sealed class BinaryReaderWith7BitEncodedInts : BinaryReader + { + public BinaryReaderWith7BitEncodedInts(Stream stream) : base(stream) + { + } + + public override short ReadInt16() + { + return unchecked((short)(ushort)base.Read7BitEncodedInt()); + } + + [CLSCompliant(false)] + public override ushort ReadUInt16() + { + return unchecked((ushort)base.Read7BitEncodedInt()); + } + + public override int ReadInt32() + { + return base.Read7BitEncodedInt(); + } + + [CLSCompliant(false)] + public override uint ReadUInt32() + { + return unchecked((uint)base.Read7BitEncodedInt()); + } + + public override long ReadInt64() + { + return unchecked((long)this.ReadUInt64()); + } + + [CLSCompliant(false)] + public override ulong ReadUInt64() + { + ulong num = 0; + int shift = 0; + while (shift < 64) { + byte b = this.ReadByte(); + num |= (ulong)(b & 127) << shift; + shift += 7; + if ((b & 128) == 0) { + return num; + } + } + throw new FormatException("Invalid 7-bit int64"); + } + } + + /// + /// A binary writer that encodes all integers as 7-bit-encoded-ints. + /// + public sealed class BinaryWriterWith7BitEncodedInts : BinaryWriter + { + public BinaryWriterWith7BitEncodedInts(Stream stream) : base(stream) + { + } + + public override void Write(short value) + { + base.Write7BitEncodedInt(unchecked((ushort)value)); + } + + [CLSCompliant(false)] + public override void Write(ushort value) + { + base.Write7BitEncodedInt(value); + } + + public override void Write(int value) + { + base.Write7BitEncodedInt(value); + } + + [CLSCompliant(false)] + public override void Write(uint value) + { + base.Write7BitEncodedInt(unchecked((int)value)); + } + + public override void Write(long value) + { + this.Write(unchecked((ulong)value)); + } + + [CLSCompliant(false)] + public override void Write(ulong value) + { + while (value >= 128) { + this.Write(unchecked((byte)(value | 128u))); + value >>= 7; + } + this.Write(unchecked((byte)value)); + } + } +} diff --git a/ICSharpCode.Decompiler/Util/BitVector16.cs b/ICSharpCode.Decompiler/Util/BitVector16.cs new file mode 100644 index 000000000..fb4de8e59 --- /dev/null +++ b/ICSharpCode.Decompiler/Util/BitVector16.cs @@ -0,0 +1,83 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Globalization; + +namespace ICSharpCode.NRefactory.Utils +{ + /// + /// Holds 16 boolean values. + /// + [Serializable] + [CLSCompliant(false)] + public struct BitVector16 : IEquatable + { + ushort data; + + public bool this[ushort mask] { + get { return (data & mask) != 0; } + set { + if (value) + data |= mask; + else + data &= unchecked((ushort)~mask); + } + } + + public ushort Data { + get { return data; } + set { data = value; } + } + + #region Equals and GetHashCode implementation + public override bool Equals(object obj) + { + if (obj is BitVector16) + return Equals((BitVector16)obj); // use Equals method below + else + return false; + } + + public bool Equals(BitVector16 other) + { + return this.data == other.data; + } + + public override int GetHashCode() + { + return data; + } + + public static bool operator ==(BitVector16 left, BitVector16 right) + { + return left.data == right.data; + } + + public static bool operator !=(BitVector16 left, BitVector16 right) + { + return left.data != right.data; + } + #endregion + + public override string ToString() + { + return data.ToString("x4", CultureInfo.InvariantCulture); + } + } +} diff --git a/ICSharpCode.Decompiler/Util/BusyManager.cs b/ICSharpCode.Decompiler/Util/BusyManager.cs new file mode 100644 index 000000000..660042b21 --- /dev/null +++ b/ICSharpCode.Decompiler/Util/BusyManager.cs @@ -0,0 +1,73 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.Utils +{ + /// + /// This class is used to prevent stack overflows by representing a 'busy' flag + /// that prevents reentrance when another call is running. + /// However, using a simple 'bool busy' is not thread-safe, so we use a + /// thread-static BusyManager. + /// + public static class BusyManager + { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible", + Justification = "Should always be used with 'var'")] + public struct BusyLock : IDisposable + { + public static readonly BusyLock Failed = new BusyLock(null); + + readonly List objectList; + + internal BusyLock(List objectList) + { + this.objectList = objectList; + } + + public bool Success { + get { return objectList != null; } + } + + public void Dispose() + { + if (objectList != null) { + objectList.RemoveAt(objectList.Count - 1); + } + } + } + + [ThreadStatic] static List _activeObjects; + + public static BusyLock Enter(object obj) + { + List activeObjects = _activeObjects; + if (activeObjects == null) + activeObjects = _activeObjects = new List(); + for (int i = 0; i < activeObjects.Count; i++) { + if (activeObjects[i] == obj) + return BusyLock.Failed; + } + activeObjects.Add(obj); + return new BusyLock(activeObjects); + } + } +} diff --git a/ICSharpCode.Decompiler/Util/CSharpPrimitiveCast.cs b/ICSharpCode.Decompiler/Util/CSharpPrimitiveCast.cs new file mode 100644 index 000000000..3a1cbd4ee --- /dev/null +++ b/ICSharpCode.Decompiler/Util/CSharpPrimitiveCast.cs @@ -0,0 +1,431 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.Utils +{ + /// + /// Static helper method for converting between primitive types. + /// + public static class CSharpPrimitiveCast + { + /// + /// Performs a conversion between primitive types. + /// Unfortunately we cannot use Convert.ChangeType because it has different semantics + /// (e.g. rounding behavior for floats, overflow, etc.), so we write down every possible primitive C# cast + /// and let the compiler figure out the exact semantics. + /// And we have to do everything twice, once in a checked-block, once in an unchecked-block. + /// + /// Overflow checking is enabled and an overflow occurred. + /// The cast is invalid, e.g. casting a boolean to an integer. + public static object Cast(TypeCode targetType, object input, bool checkForOverflow) + { + if (input == null) + return null; + if (checkForOverflow) + return CSharpPrimitiveCastChecked(targetType, input); + else + return CSharpPrimitiveCastUnchecked(targetType, input); + } + + static object CSharpPrimitiveCastChecked(TypeCode targetType, object input) + { + checked { + TypeCode sourceType = Type.GetTypeCode(input.GetType()); + if (sourceType == targetType) + return input; + switch (targetType) { + case TypeCode.Char: + switch (sourceType) { + case TypeCode.SByte: return (char)(sbyte)input; + case TypeCode.Byte: return (char)(byte)input; + case TypeCode.Int16: return (char)(short)input; + case TypeCode.UInt16: return (char)(ushort)input; + case TypeCode.Int32: return (char)(int)input; + case TypeCode.UInt32: return (char)(uint)input; + case TypeCode.Int64: return (char)(long)input; + case TypeCode.UInt64: return (char)(ulong)input; + case TypeCode.Single: return (char)(float)input; + case TypeCode.Double: return (char)(double)input; + case TypeCode.Decimal: return (char)(decimal)input; + } + break; + case TypeCode.SByte: + switch (sourceType) { + case TypeCode.Char: return (sbyte)(char)input; + case TypeCode.Byte: return (sbyte)(byte)input; + case TypeCode.Int16: return (sbyte)(short)input; + case TypeCode.UInt16: return (sbyte)(ushort)input; + case TypeCode.Int32: return (sbyte)(int)input; + case TypeCode.UInt32: return (sbyte)(uint)input; + case TypeCode.Int64: return (sbyte)(long)input; + case TypeCode.UInt64: return (sbyte)(ulong)input; + case TypeCode.Single: return (sbyte)(float)input; + case TypeCode.Double: return (sbyte)(double)input; + case TypeCode.Decimal: return (sbyte)(decimal)input; + } + break; + case TypeCode.Byte: + switch (sourceType) { + case TypeCode.Char: return (byte)(char)input; + case TypeCode.SByte: return (byte)(sbyte)input; + case TypeCode.Int16: return (byte)(short)input; + case TypeCode.UInt16: return (byte)(ushort)input; + case TypeCode.Int32: return (byte)(int)input; + case TypeCode.UInt32: return (byte)(uint)input; + case TypeCode.Int64: return (byte)(long)input; + case TypeCode.UInt64: return (byte)(ulong)input; + case TypeCode.Single: return (byte)(float)input; + case TypeCode.Double: return (byte)(double)input; + case TypeCode.Decimal: return (byte)(decimal)input; + } + break; + case TypeCode.Int16: + switch (sourceType) { + case TypeCode.Char: return (short)(char)input; + case TypeCode.SByte: return (short)(sbyte)input; + case TypeCode.Byte: return (short)(byte)input; + case TypeCode.UInt16: return (short)(ushort)input; + case TypeCode.Int32: return (short)(int)input; + case TypeCode.UInt32: return (short)(uint)input; + case TypeCode.Int64: return (short)(long)input; + case TypeCode.UInt64: return (short)(ulong)input; + case TypeCode.Single: return (short)(float)input; + case TypeCode.Double: return (short)(double)input; + case TypeCode.Decimal: return (short)(decimal)input; + } + break; + case TypeCode.UInt16: + switch (sourceType) { + case TypeCode.Char: return (ushort)(char)input; + case TypeCode.SByte: return (ushort)(sbyte)input; + case TypeCode.Byte: return (ushort)(byte)input; + case TypeCode.Int16: return (ushort)(short)input; + case TypeCode.Int32: return (ushort)(int)input; + case TypeCode.UInt32: return (ushort)(uint)input; + case TypeCode.Int64: return (ushort)(long)input; + case TypeCode.UInt64: return (ushort)(ulong)input; + case TypeCode.Single: return (ushort)(float)input; + case TypeCode.Double: return (ushort)(double)input; + case TypeCode.Decimal: return (ushort)(decimal)input; + } + break; + case TypeCode.Int32: + switch (sourceType) { + case TypeCode.Char: return (int)(char)input; + case TypeCode.SByte: return (int)(sbyte)input; + case TypeCode.Byte: return (int)(byte)input; + case TypeCode.Int16: return (int)(short)input; + case TypeCode.UInt16: return (int)(ushort)input; + case TypeCode.UInt32: return (int)(uint)input; + case TypeCode.Int64: return (int)(long)input; + case TypeCode.UInt64: return (int)(ulong)input; + case TypeCode.Single: return (int)(float)input; + case TypeCode.Double: return (int)(double)input; + case TypeCode.Decimal: return (int)(decimal)input; + } + break; + case TypeCode.UInt32: + switch (sourceType) { + case TypeCode.Char: return (uint)(char)input; + case TypeCode.SByte: return (uint)(sbyte)input; + case TypeCode.Byte: return (uint)(byte)input; + case TypeCode.Int16: return (uint)(short)input; + case TypeCode.UInt16: return (uint)(ushort)input; + case TypeCode.Int32: return (uint)(int)input; + case TypeCode.Int64: return (uint)(long)input; + case TypeCode.UInt64: return (uint)(ulong)input; + case TypeCode.Single: return (uint)(float)input; + case TypeCode.Double: return (uint)(double)input; + case TypeCode.Decimal: return (uint)(decimal)input; + } + break; + case TypeCode.Int64: + switch (sourceType) { + case TypeCode.Char: return (long)(char)input; + case TypeCode.SByte: return (long)(sbyte)input; + case TypeCode.Byte: return (long)(byte)input; + case TypeCode.Int16: return (long)(short)input; + case TypeCode.UInt16: return (long)(ushort)input; + case TypeCode.Int32: return (long)(int)input; + case TypeCode.UInt32: return (long)(uint)input; + case TypeCode.UInt64: return (long)(ulong)input; + case TypeCode.Single: return (long)(float)input; + case TypeCode.Double: return (long)(double)input; + case TypeCode.Decimal: return (long)(decimal)input; + } + break; + case TypeCode.UInt64: + switch (sourceType) { + case TypeCode.Char: return (ulong)(char)input; + case TypeCode.SByte: return (ulong)(sbyte)input; + case TypeCode.Byte: return (ulong)(byte)input; + case TypeCode.Int16: return (ulong)(short)input; + case TypeCode.UInt16: return (ulong)(ushort)input; + case TypeCode.Int32: return (ulong)(int)input; + case TypeCode.UInt32: return (ulong)(uint)input; + case TypeCode.Int64: return (ulong)(long)input; + case TypeCode.Single: return (ulong)(float)input; + case TypeCode.Double: return (ulong)(double)input; + case TypeCode.Decimal: return (ulong)(decimal)input; + } + break; + case TypeCode.Single: + switch (sourceType) { + case TypeCode.Char: return (float)(char)input; + case TypeCode.SByte: return (float)(sbyte)input; + case TypeCode.Byte: return (float)(byte)input; + case TypeCode.Int16: return (float)(short)input; + case TypeCode.UInt16: return (float)(ushort)input; + case TypeCode.Int32: return (float)(int)input; + case TypeCode.UInt32: return (float)(uint)input; + case TypeCode.Int64: return (float)(long)input; + case TypeCode.UInt64: return (float)(ulong)input; + case TypeCode.Double: return (float)(double)input; + case TypeCode.Decimal: return (float)(decimal)input; + } + break; + case TypeCode.Double: + switch (sourceType) { + case TypeCode.Char: return (double)(char)input; + case TypeCode.SByte: return (double)(sbyte)input; + case TypeCode.Byte: return (double)(byte)input; + case TypeCode.Int16: return (double)(short)input; + case TypeCode.UInt16: return (double)(ushort)input; + case TypeCode.Int32: return (double)(int)input; + case TypeCode.UInt32: return (double)(uint)input; + case TypeCode.Int64: return (double)(long)input; + case TypeCode.UInt64: return (double)(ulong)input; + case TypeCode.Single: return (double)(float)input; + case TypeCode.Decimal: return (double)(decimal)input; + } + break; + case TypeCode.Decimal: + switch (sourceType) { + case TypeCode.Char: return (decimal)(char)input; + case TypeCode.SByte: return (decimal)(sbyte)input; + case TypeCode.Byte: return (decimal)(byte)input; + case TypeCode.Int16: return (decimal)(short)input; + case TypeCode.UInt16: return (decimal)(ushort)input; + case TypeCode.Int32: return (decimal)(int)input; + case TypeCode.UInt32: return (decimal)(uint)input; + case TypeCode.Int64: return (decimal)(long)input; + case TypeCode.UInt64: return (decimal)(ulong)input; + case TypeCode.Single: return (decimal)(float)input; + case TypeCode.Double: return (decimal)(double)input; + } + break; + } + throw new InvalidCastException("Cast from " + sourceType + " to " + targetType + "not supported."); + } + } + + static object CSharpPrimitiveCastUnchecked(TypeCode targetType, object input) + { + unchecked { + TypeCode sourceType = Type.GetTypeCode(input.GetType()); + if (sourceType == targetType) + return input; + switch (targetType) { + case TypeCode.Char: + switch (sourceType) { + case TypeCode.SByte: return (char)(sbyte)input; + case TypeCode.Byte: return (char)(byte)input; + case TypeCode.Int16: return (char)(short)input; + case TypeCode.UInt16: return (char)(ushort)input; + case TypeCode.Int32: return (char)(int)input; + case TypeCode.UInt32: return (char)(uint)input; + case TypeCode.Int64: return (char)(long)input; + case TypeCode.UInt64: return (char)(ulong)input; + case TypeCode.Single: return (char)(float)input; + case TypeCode.Double: return (char)(double)input; + case TypeCode.Decimal: return (char)(decimal)input; + } + break; + case TypeCode.SByte: + switch (sourceType) { + case TypeCode.Char: return (sbyte)(char)input; + case TypeCode.Byte: return (sbyte)(byte)input; + case TypeCode.Int16: return (sbyte)(short)input; + case TypeCode.UInt16: return (sbyte)(ushort)input; + case TypeCode.Int32: return (sbyte)(int)input; + case TypeCode.UInt32: return (sbyte)(uint)input; + case TypeCode.Int64: return (sbyte)(long)input; + case TypeCode.UInt64: return (sbyte)(ulong)input; + case TypeCode.Single: return (sbyte)(float)input; + case TypeCode.Double: return (sbyte)(double)input; + case TypeCode.Decimal: return (sbyte)(decimal)input; + } + break; + case TypeCode.Byte: + switch (sourceType) { + case TypeCode.Char: return (byte)(char)input; + case TypeCode.SByte: return (byte)(sbyte)input; + case TypeCode.Int16: return (byte)(short)input; + case TypeCode.UInt16: return (byte)(ushort)input; + case TypeCode.Int32: return (byte)(int)input; + case TypeCode.UInt32: return (byte)(uint)input; + case TypeCode.Int64: return (byte)(long)input; + case TypeCode.UInt64: return (byte)(ulong)input; + case TypeCode.Single: return (byte)(float)input; + case TypeCode.Double: return (byte)(double)input; + case TypeCode.Decimal: return (byte)(decimal)input; + } + break; + case TypeCode.Int16: + switch (sourceType) { + case TypeCode.Char: return (short)(char)input; + case TypeCode.SByte: return (short)(sbyte)input; + case TypeCode.Byte: return (short)(byte)input; + case TypeCode.UInt16: return (short)(ushort)input; + case TypeCode.Int32: return (short)(int)input; + case TypeCode.UInt32: return (short)(uint)input; + case TypeCode.Int64: return (short)(long)input; + case TypeCode.UInt64: return (short)(ulong)input; + case TypeCode.Single: return (short)(float)input; + case TypeCode.Double: return (short)(double)input; + case TypeCode.Decimal: return (short)(decimal)input; + } + break; + case TypeCode.UInt16: + switch (sourceType) { + case TypeCode.Char: return (ushort)(char)input; + case TypeCode.SByte: return (ushort)(sbyte)input; + case TypeCode.Byte: return (ushort)(byte)input; + case TypeCode.Int16: return (ushort)(short)input; + case TypeCode.Int32: return (ushort)(int)input; + case TypeCode.UInt32: return (ushort)(uint)input; + case TypeCode.Int64: return (ushort)(long)input; + case TypeCode.UInt64: return (ushort)(ulong)input; + case TypeCode.Single: return (ushort)(float)input; + case TypeCode.Double: return (ushort)(double)input; + case TypeCode.Decimal: return (ushort)(decimal)input; + } + break; + case TypeCode.Int32: + switch (sourceType) { + case TypeCode.Char: return (int)(char)input; + case TypeCode.SByte: return (int)(sbyte)input; + case TypeCode.Byte: return (int)(byte)input; + case TypeCode.Int16: return (int)(short)input; + case TypeCode.UInt16: return (int)(ushort)input; + case TypeCode.UInt32: return (int)(uint)input; + case TypeCode.Int64: return (int)(long)input; + case TypeCode.UInt64: return (int)(ulong)input; + case TypeCode.Single: return (int)(float)input; + case TypeCode.Double: return (int)(double)input; + case TypeCode.Decimal: return (int)(decimal)input; + } + break; + case TypeCode.UInt32: + switch (sourceType) { + case TypeCode.Char: return (uint)(char)input; + case TypeCode.SByte: return (uint)(sbyte)input; + case TypeCode.Byte: return (uint)(byte)input; + case TypeCode.Int16: return (uint)(short)input; + case TypeCode.UInt16: return (uint)(ushort)input; + case TypeCode.Int32: return (uint)(int)input; + case TypeCode.Int64: return (uint)(long)input; + case TypeCode.UInt64: return (uint)(ulong)input; + case TypeCode.Single: return (uint)(float)input; + case TypeCode.Double: return (uint)(double)input; + case TypeCode.Decimal: return (uint)(decimal)input; + } + break; + case TypeCode.Int64: + switch (sourceType) { + case TypeCode.Char: return (long)(char)input; + case TypeCode.SByte: return (long)(sbyte)input; + case TypeCode.Byte: return (long)(byte)input; + case TypeCode.Int16: return (long)(short)input; + case TypeCode.UInt16: return (long)(ushort)input; + case TypeCode.Int32: return (long)(int)input; + case TypeCode.UInt32: return (long)(uint)input; + case TypeCode.UInt64: return (long)(ulong)input; + case TypeCode.Single: return (long)(float)input; + case TypeCode.Double: return (long)(double)input; + case TypeCode.Decimal: return (long)(decimal)input; + } + break; + case TypeCode.UInt64: + switch (sourceType) { + case TypeCode.Char: return (ulong)(char)input; + case TypeCode.SByte: return (ulong)(sbyte)input; + case TypeCode.Byte: return (ulong)(byte)input; + case TypeCode.Int16: return (ulong)(short)input; + case TypeCode.UInt16: return (ulong)(ushort)input; + case TypeCode.Int32: return (ulong)(int)input; + case TypeCode.UInt32: return (ulong)(uint)input; + case TypeCode.Int64: return (ulong)(long)input; + case TypeCode.Single: return (ulong)(float)input; + case TypeCode.Double: return (ulong)(double)input; + case TypeCode.Decimal: return (ulong)(decimal)input; + } + break; + case TypeCode.Single: + switch (sourceType) { + case TypeCode.Char: return (float)(char)input; + case TypeCode.SByte: return (float)(sbyte)input; + case TypeCode.Byte: return (float)(byte)input; + case TypeCode.Int16: return (float)(short)input; + case TypeCode.UInt16: return (float)(ushort)input; + case TypeCode.Int32: return (float)(int)input; + case TypeCode.UInt32: return (float)(uint)input; + case TypeCode.Int64: return (float)(long)input; + case TypeCode.UInt64: return (float)(ulong)input; + case TypeCode.Double: return (float)(double)input; + case TypeCode.Decimal: return (float)(decimal)input; + } + break; + case TypeCode.Double: + switch (sourceType) { + case TypeCode.Char: return (double)(char)input; + case TypeCode.SByte: return (double)(sbyte)input; + case TypeCode.Byte: return (double)(byte)input; + case TypeCode.Int16: return (double)(short)input; + case TypeCode.UInt16: return (double)(ushort)input; + case TypeCode.Int32: return (double)(int)input; + case TypeCode.UInt32: return (double)(uint)input; + case TypeCode.Int64: return (double)(long)input; + case TypeCode.UInt64: return (double)(ulong)input; + case TypeCode.Single: return (double)(float)input; + case TypeCode.Decimal: return (double)(decimal)input; + } + break; + case TypeCode.Decimal: + switch (sourceType) { + case TypeCode.Char: return (decimal)(char)input; + case TypeCode.SByte: return (decimal)(sbyte)input; + case TypeCode.Byte: return (decimal)(byte)input; + case TypeCode.Int16: return (decimal)(short)input; + case TypeCode.UInt16: return (decimal)(ushort)input; + case TypeCode.Int32: return (decimal)(int)input; + case TypeCode.UInt32: return (decimal)(uint)input; + case TypeCode.Int64: return (decimal)(long)input; + case TypeCode.UInt64: return (decimal)(ulong)input; + case TypeCode.Single: return (decimal)(float)input; + case TypeCode.Double: return (decimal)(double)input; + } + break; + } + throw new InvalidCastException("Cast from " + sourceType + " to " + targetType + " not supported."); + } + } + } +} diff --git a/ICSharpCode.Decompiler/Util/CacheManager.cs b/ICSharpCode.Decompiler/Util/CacheManager.cs new file mode 100644 index 000000000..f28e8970d --- /dev/null +++ b/ICSharpCode.Decompiler/Util/CacheManager.cs @@ -0,0 +1,59 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Concurrent; +using System.Collections.Generic; +using System.Threading; + +namespace ICSharpCode.NRefactory.Utils +{ + /// + /// Allows caching values for a specific compilation. + /// A CacheManager consists of a for shared instances (shared among all threads working with that resolve context). + /// + /// This class is thread-safe + public sealed class CacheManager + { + readonly ConcurrentDictionary sharedDict = new ConcurrentDictionary(ReferenceComparer.Instance); + // There used to be a thread-local dictionary here, but I removed it as it was causing memory + // leaks in some use cases. + + public object GetShared(object key) + { + object value; + sharedDict.TryGetValue(key, out value); + return value; + } + + public object GetOrAddShared(object key, Func valueFactory) + { + return sharedDict.GetOrAdd(key, valueFactory); + } + + public object GetOrAddShared(object key, object value) + { + return sharedDict.GetOrAdd(key, value); + } + + public void SetShared(object key, object value) + { + sharedDict[key] = value; + } + } +} diff --git a/ICSharpCode.Decompiler/Util/CallbackOnDispose.cs b/ICSharpCode.Decompiler/Util/CallbackOnDispose.cs new file mode 100644 index 000000000..5dfa5e093 --- /dev/null +++ b/ICSharpCode.Decompiler/Util/CallbackOnDispose.cs @@ -0,0 +1,51 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Diagnostics; +using System.Threading; + +namespace ICSharpCode.NRefactory.Utils +{ + /// + /// Invokes an action when it is disposed. + /// + /// + /// This class ensures the callback is invoked at most once, + /// even when Dispose is called on multiple threads. + /// + public sealed class CallbackOnDispose : IDisposable + { + Action action; + + public CallbackOnDispose(Action action) + { + if (action == null) + throw new ArgumentNullException("action"); + this.action = action; + } + + public void Dispose() + { + Action a = Interlocked.Exchange(ref action, null); + if (a != null) { + a(); + } + } + } +} diff --git a/ICSharpCode.Decompiler/Util/EmptyList.cs b/ICSharpCode.Decompiler/Util/EmptyList.cs new file mode 100644 index 000000000..90f0f8627 --- /dev/null +++ b/ICSharpCode.Decompiler/Util/EmptyList.cs @@ -0,0 +1,118 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace ICSharpCode.NRefactory +{ + [Serializable] + public sealed class EmptyList : IList, IEnumerator + #if NET_4_5 + , IReadOnlyList + #endif + { + public static readonly EmptyList Instance = new EmptyList(); + + private EmptyList() {} + + public T this[int index] { + get { throw new ArgumentOutOfRangeException("index"); } + set { throw new ArgumentOutOfRangeException("index"); } + } + + public int Count { + get { return 0; } + } + + bool ICollection.IsReadOnly { + get { return true; } + } + + int IList.IndexOf(T item) + { + return -1; + } + + void IList.Insert(int index, T item) + { + throw new NotSupportedException(); + } + + void IList.RemoveAt(int index) + { + throw new NotSupportedException(); + } + + void ICollection.Add(T item) + { + throw new NotSupportedException(); + } + + void ICollection.Clear() + { + } + + bool ICollection.Contains(T item) + { + return false; + } + + void ICollection.CopyTo(T[] array, int arrayIndex) + { + } + + bool ICollection.Remove(T item) + { + return false; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this; + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this; + } + + T IEnumerator.Current { + get { return default(T); } + } + + object IEnumerator.Current { + get { return default(T); } + } + + void IDisposable.Dispose() + { + } + + bool IEnumerator.MoveNext() + { + return false; + } + + void IEnumerator.Reset() + { + } + } +} diff --git a/ICSharpCode.Decompiler/Util/ExtensionMethods.cs b/ICSharpCode.Decompiler/Util/ExtensionMethods.cs new file mode 100644 index 000000000..e5829b2c2 --- /dev/null +++ b/ICSharpCode.Decompiler/Util/ExtensionMethods.cs @@ -0,0 +1,44 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.Utils +{ + /// + /// Contains extension methods for use within NRefactory. + /// + static class ExtensionMethods + { + public static void AddRange(this ICollection target, IEnumerable input) + { + foreach (T item in input) + target.Add(item); + } + + public static Predicate And(this Predicate filter1, Predicate filter2) + { + if (filter1 == null) + return filter2; + if (filter2 == null) + return filter1; + return m => filter1(m) && filter2(m); + } + } +} diff --git a/ICSharpCode.Decompiler/Util/FastSerializer.cs b/ICSharpCode.Decompiler/Util/FastSerializer.cs new file mode 100644 index 000000000..3fc5dec3f --- /dev/null +++ b/ICSharpCode.Decompiler/Util/FastSerializer.cs @@ -0,0 +1,1371 @@ +// Copyright (c) 2011 Daniel Grunwald +// +// 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 System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.Serialization; + +namespace ICSharpCode.NRefactory.Utils +{ + public class FastSerializer + { + #region Properties + /// + /// Gets/Sets the serialization binder that is being used. + /// The default value is null, which will cause the FastSerializer to use the + /// full assembly and type names. + /// + public SerializationBinder SerializationBinder { get; set; } + + /// + /// Can be used to set several 'fixed' instances. + /// When serializing, such instances will not be included; and any references to a fixed instance + /// will be stored as the index in this array. + /// When deserializing, the same (or equivalent) instances must be specified, and the deserializer + /// will use them in place of the fixed instances. + /// + public object[] FixedInstances { get; set; } + #endregion + + #region Constants + const int magic = 0x71D28A5E; + + const byte Type_ReferenceType = 1; + const byte Type_ValueType = 2; + const byte Type_SZArray = 3; + const byte Type_ParameterizedType = 4; + #endregion + + #region Serialization + sealed class SerializationType + { + public readonly int ID; + public readonly Type Type; + + public SerializationType(int iD, Type type) + { + this.ID = iD; + this.Type = type; + } + + public ObjectScanner Scanner; + public ObjectWriter Writer; + public string TypeName; + public int AssemblyNameID; + } + + sealed class SerializationContext + { + readonly Dictionary objectToID = new Dictionary(ReferenceComparer.Instance); + readonly List instances = new List(); // index: object ID + readonly List objectTypes = new List(); // index: object ID + SerializationType stringType; + + readonly Dictionary typeMap = new Dictionary(); + readonly List types = new List(); + + readonly Dictionary assemblyNameToID = new Dictionary(); + readonly List assemblyNames = new List(); + + readonly FastSerializer fastSerializer; + public readonly BinaryWriter writer; + int fixedInstanceCount; + + internal SerializationContext(FastSerializer fastSerializer, BinaryWriter writer) + { + this.fastSerializer = fastSerializer; + this.writer = writer; + instances.Add(null); // use object ID 0 for null + objectTypes.Add(null); + } + + #region Scanning + public void MarkFixedInstances(object[] fixedInstances) + { + if (fixedInstances == null) + return; + foreach (object obj in fixedInstances) { + if (!objectToID.ContainsKey(obj)) { + objectToID.Add(obj, instances.Count); + instances.Add(obj); + fixedInstanceCount++; + } + } + } + + /// + /// Marks an instance for future scanning. + /// + public void Mark(object instance) + { + if (instance == null || objectToID.ContainsKey(instance)) + return; + Log(" Mark {0}", instance.GetType().Name); + + objectToID.Add(instance, instances.Count); + instances.Add(instance); + } + + internal void Scan() + { + Log("Scanning..."); + // starting from 1, because index 0 is null + // Also, do not scan any of the 'fixed instances'. + for (int i = 1 + fixedInstanceCount; i < instances.Count; i++) { + object instance = instances[i]; + ISerializable serializable = instance as ISerializable; + Type type = instance.GetType(); + Log("Scan #{0}: {1}", i, type.Name); + SerializationType sType = MarkType(type); + objectTypes.Add(sType); + if (serializable != null) { + SerializationInfo info = new SerializationInfo(type, fastSerializer.formatterConverter); + serializable.GetObjectData(info, fastSerializer.streamingContext); + instances[i] = info; + foreach (SerializationEntry entry in info) { + Mark(entry.Value); + } + sType.Writer = serializationInfoWriter; + } else { + ObjectScanner objectScanner = sType.Scanner; + if (objectScanner == null) { + objectScanner = fastSerializer.GetScanner(type); + sType.Scanner = objectScanner; + sType.Writer = fastSerializer.GetWriter(type); + } + objectScanner(this, instance); + } + } + } + #endregion + + #region Scan Types + SerializationType MarkType(Type type) + { + SerializationType sType; + if (!typeMap.TryGetValue(type, out sType)) { + string assemblyName = null; + string typeName = null; + if (type.HasElementType) { + Debug.Assert(type.IsArray); + MarkType(type.GetElementType()); + } else if (type.IsGenericType && !type.IsGenericTypeDefinition) { + MarkType(type.GetGenericTypeDefinition()); + foreach (Type typeArg in type.GetGenericArguments()) + MarkType(typeArg); + } else if (type.IsGenericParameter) { + throw new NotSupportedException(); + } else { + var serializationBinder = fastSerializer.SerializationBinder; + if (serializationBinder != null) { + serializationBinder.BindToName(type, out assemblyName, out typeName); + } else { + assemblyName = type.Assembly.FullName; + typeName = type.FullName; + Debug.Assert(typeName != null); + } + } + + sType = new SerializationType(typeMap.Count, type); + sType.TypeName = typeName; + if (assemblyName != null) { + if (!assemblyNameToID.TryGetValue(assemblyName, out sType.AssemblyNameID)) { + sType.AssemblyNameID = assemblyNames.Count; + assemblyNameToID.Add(assemblyName, sType.AssemblyNameID); + assemblyNames.Add(assemblyName); + Log("Registered assembly #{0}: {1}", sType.AssemblyNameID, assemblyName); + } + } + typeMap.Add(type, sType); + types.Add(sType); + Log("Registered type %{0}: {1}", sType.ID, type); + if (type == typeof(string)) { + stringType = sType; + } + } + return sType; + } + + internal void ScanTypes() + { + for (int i = 0; i < types.Count; i++) { + Type type = types[i].Type; + if (type.IsGenericTypeDefinition || type.HasElementType) + continue; + if (typeof(ISerializable).IsAssignableFrom(type)) + continue; + foreach (FieldInfo field in GetSerializableFields(type)) { + MarkType(field.FieldType); + } + } + } + #endregion + + #region Writing + public void WriteObjectID(object instance) + { + int id = (instance == null) ? 0 : objectToID[instance]; + if (instances.Count <= ushort.MaxValue) + writer.Write((ushort)id); + else + writer.Write(id); + } + + void WriteTypeID(Type type) + { + Debug.Assert(typeMap.ContainsKey(type)); + int typeID = typeMap[type].ID; + if (types.Count <= ushort.MaxValue) + writer.Write((ushort)typeID); + else + writer.Write(typeID); + } + + internal void Write() + { + Log("Writing..."); + writer.Write(magic); + // Write out type information + writer.Write(instances.Count); + writer.Write(types.Count); + writer.Write(assemblyNames.Count); + writer.Write(fixedInstanceCount); + + foreach (string assemblyName in assemblyNames) { + writer.Write(assemblyName); + } + + foreach (SerializationType sType in types) { + Type type = sType.Type; + if (type.HasElementType) { + if (type.IsArray) { + if (type.GetArrayRank() == 1) + writer.Write(Type_SZArray); + else + throw new NotSupportedException(); + } else { + throw new NotSupportedException(); + } + WriteTypeID(type.GetElementType()); + } else if (type.IsGenericType && !type.IsGenericTypeDefinition) { + writer.Write(Type_ParameterizedType); + WriteTypeID(type.GetGenericTypeDefinition()); + foreach (Type typeArg in type.GetGenericArguments()) { + WriteTypeID(typeArg); + } + } else { + if (type.IsValueType) { + writer.Write(Type_ValueType); + } else { + writer.Write(Type_ReferenceType); + } + if (assemblyNames.Count <= ushort.MaxValue) + writer.Write((ushort)sType.AssemblyNameID); + else + writer.Write(sType.AssemblyNameID); + writer.Write(sType.TypeName); + } + } + foreach (SerializationType sType in types) { + Type type = sType.Type; + if (type.IsGenericTypeDefinition || type.HasElementType) + continue; + writer.Write(FastSerializerVersionAttribute.GetVersionNumber(type)); + if (type.IsPrimitive || typeof(ISerializable).IsAssignableFrom(type)) { + writer.Write(byte.MaxValue); + } else { + var fields = GetSerializableFields(type); + if (fields.Count >= byte.MaxValue) + throw new SerializationException("Too many fields."); + writer.Write((byte)fields.Count); + foreach (var field in fields) { + WriteTypeID(field.FieldType); + writer.Write(field.Name); + } + } + } + + // Write out information necessary to create the instances + // starting from 1, because index 0 is null + for (int i = 1 + fixedInstanceCount; i < instances.Count; i++) { + SerializationType sType = objectTypes[i]; + if (types.Count <= ushort.MaxValue) + writer.Write((ushort)sType.ID); + else + writer.Write(sType.ID); + if (sType == stringType) { + // Strings are written to the output immediately + // - we can't create an empty string and fill it later + writer.Write((string)instances[i]); + } else if (sType.Type.IsArray) { + // For arrays, write down the length, because we need that to create the array instance + writer.Write(((Array)instances[i]).Length); + } + } + // Write out information necessary to fill data into the instances + for (int i = 1 + fixedInstanceCount; i < instances.Count; i++) { + Log("0x{2:x6}, Write #{0}: {1}", i, objectTypes[i].Type.Name, writer.BaseStream.Position); + objectTypes[i].Writer(this, instances[i]); + } + Log("Serialization done."); + } + #endregion + } + + #region Object Scanners + delegate void ObjectScanner(SerializationContext context, object instance); + + static readonly MethodInfo mark = typeof(SerializationContext).GetMethod("Mark", new[] { typeof(object) }); + static readonly FieldInfo writerField = typeof(SerializationContext).GetField("writer"); + + Dictionary scanners = new Dictionary(); + + ObjectScanner GetScanner(Type type) + { + ObjectScanner scanner; + if (!scanners.TryGetValue(type, out scanner)) { + scanner = CreateScanner(type); + scanners.Add(type, scanner); + } + return scanner; + } + + ObjectScanner CreateScanner(Type type) + { + bool isArray = type.IsArray; + if (isArray) { + if (type.GetArrayRank() != 1) + throw new NotSupportedException(); + type = type.GetElementType(); + if (!type.IsValueType) { + return delegate (SerializationContext context, object array) { + foreach (object val in (object[])array) { + context.Mark(val); + } + }; + } + } + for (Type baseType = type; baseType != null; baseType = baseType.BaseType) { + if (!baseType.IsSerializable) + throw new SerializationException("Type " + baseType + " is not [Serializable]."); + } + List fields = GetSerializableFields(type); + fields.RemoveAll(f => !IsReferenceOrContainsReferences(f.FieldType)); + if (fields.Count == 0) { + // The scanner has nothing to do for this object. + return delegate { }; + } + + DynamicMethod dynamicMethod = new DynamicMethod( + (isArray ? "ScanArray_" : "Scan_") + type.Name, + typeof(void), new [] { typeof(SerializationContext), typeof(object) }, + true); + ILGenerator il = dynamicMethod.GetILGenerator(); + + + if (isArray) { + var instance = il.DeclareLocal(type.MakeArrayType()); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Castclass, type.MakeArrayType()); + il.Emit(OpCodes.Stloc, instance); // instance = (type[])arg_1; + + // for (int i = 0; i < instance.Length; i++) scan instance[i]; + var loopStart = il.DefineLabel(); + var loopHead = il.DefineLabel(); + var loopVariable = il.DeclareLocal(typeof(int)); + il.Emit(OpCodes.Ldc_I4_0); + il.Emit(OpCodes.Stloc, loopVariable); // loopVariable = 0 + il.Emit(OpCodes.Br, loopHead); // goto loopHead; + + il.MarkLabel(loopStart); + + il.Emit(OpCodes.Ldloc, instance); // instance + il.Emit(OpCodes.Ldloc, loopVariable); // instance, loopVariable + il.Emit(OpCodes.Ldelem, type); // &instance[loopVariable] + EmitScanValueType(il, type); + + + il.Emit(OpCodes.Ldloc, loopVariable); // loopVariable + il.Emit(OpCodes.Ldc_I4_1); // loopVariable, 1 + il.Emit(OpCodes.Add); // loopVariable+1 + il.Emit(OpCodes.Stloc, loopVariable); // loopVariable++; + + il.MarkLabel(loopHead); + il.Emit(OpCodes.Ldloc, loopVariable); // loopVariable + il.Emit(OpCodes.Ldloc, instance); // loopVariable, instance + il.Emit(OpCodes.Ldlen); // loopVariable, instance.Length + il.Emit(OpCodes.Conv_I4); + il.Emit(OpCodes.Blt, loopStart); // if (loopVariable < instance.Length) goto loopStart; + } else if (type.IsValueType) { + // boxed value type + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Unbox_Any, type); + EmitScanValueType(il, type); + } else { + // reference type + var instance = il.DeclareLocal(type); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Castclass, type); + il.Emit(OpCodes.Stloc, instance); // instance = (type)arg_1; + + foreach (FieldInfo field in fields) { + EmitScanField(il, instance, field); // scan instance.Field + } + } + il.Emit(OpCodes.Ret); + return (ObjectScanner)dynamicMethod.CreateDelegate(typeof(ObjectScanner)); + } + + /// + /// Emit 'scan instance.Field'. + /// Stack transition: ... => ... + /// + void EmitScanField(ILGenerator il, LocalBuilder instance, FieldInfo field) + { + if (field.FieldType.IsValueType) { + il.Emit(OpCodes.Ldloc, instance); // instance + il.Emit(OpCodes.Ldfld, field); // instance.field + EmitScanValueType(il, field.FieldType); + } else { + il.Emit(OpCodes.Ldarg_0); // context + il.Emit(OpCodes.Ldloc, instance); // context, instance + il.Emit(OpCodes.Ldfld, field); // context, instance.field + il.Emit(OpCodes.Call, mark); // context.Mark(instance.field); + } + } + + /// + /// Stack transition: ..., value => ... + /// + void EmitScanValueType(ILGenerator il, Type valType) + { + var fieldRef = il.DeclareLocal(valType); + il.Emit(OpCodes.Stloc, fieldRef); + + foreach (FieldInfo field in GetSerializableFields(valType)) { + if (IsReferenceOrContainsReferences(field.FieldType)) { + EmitScanField(il, fieldRef, field); + } + } + } + + static List GetSerializableFields(Type type) + { + List fields = new List(); + for (Type baseType = type; baseType != null; baseType = baseType.BaseType) { + FieldInfo[] declFields = baseType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly); + Array.Sort(declFields, (a,b) => string.Compare(a.Name, b.Name, StringComparison.Ordinal)); + fields.AddRange(declFields); + } + fields.RemoveAll(f => f.IsNotSerialized); + return fields; + } + + static bool IsReferenceOrContainsReferences(Type type) + { + if (!type.IsValueType) + return true; + if (type.IsPrimitive) + return false; + foreach (FieldInfo field in GetSerializableFields(type)) { + if (IsReferenceOrContainsReferences(field.FieldType)) + return true; + } + return false; + } + #endregion + + #region Object Writers + delegate void ObjectWriter(SerializationContext context, object instance); + + static readonly MethodInfo writeObjectID = typeof(SerializationContext).GetMethod("WriteObjectID", new[] { typeof(object) }); + + static readonly MethodInfo writeByte = typeof(BinaryWriter).GetMethod("Write", new[] { typeof(byte) }); + static readonly MethodInfo writeShort = typeof(BinaryWriter).GetMethod("Write", new[] { typeof(short) }); + static readonly MethodInfo writeInt = typeof(BinaryWriter).GetMethod("Write", new[] { typeof(int) }); + static readonly MethodInfo writeLong = typeof(BinaryWriter).GetMethod("Write", new[] { typeof(long) }); + static readonly MethodInfo writeFloat = typeof(BinaryWriter).GetMethod("Write", new[] { typeof(float) }); + static readonly MethodInfo writeDouble = typeof(BinaryWriter).GetMethod("Write", new[] { typeof(double) }); + OpCode callVirt = OpCodes.Callvirt; + + static readonly ObjectWriter serializationInfoWriter = delegate(SerializationContext context, object instance) { + BinaryWriter writer = context.writer; + SerializationInfo info = (SerializationInfo)instance; + writer.Write(info.MemberCount); + foreach (SerializationEntry entry in info) { + writer.Write(entry.Name); + context.WriteObjectID(entry.Value); + } + }; + + Dictionary writers = new Dictionary(); + + ObjectWriter GetWriter(Type type) + { + ObjectWriter writer; + if (!writers.TryGetValue(type, out writer)) { + writer = CreateWriter(type); + writers.Add(type, writer); + } + return writer; + } + + ObjectWriter CreateWriter(Type type) + { + if (type == typeof(string)) { + // String contents are written in the object creation section, + // not into the field value section. + return delegate {}; + } + bool isArray = type.IsArray; + if (isArray) { + if (type.GetArrayRank() != 1) + throw new NotSupportedException(); + type = type.GetElementType(); + if (!type.IsValueType) { + return delegate (SerializationContext context, object array) { + foreach (object val in (object[])array) { + context.WriteObjectID(val); + } + }; + } else if (type == typeof(byte)) { + return delegate (SerializationContext context, object array) { + context.writer.Write((byte[])array); + }; + } + } + List fields = GetSerializableFields(type); + if (fields.Count == 0) { + // The writer has nothing to do for this object. + return delegate { }; + } + + + DynamicMethod dynamicMethod = new DynamicMethod( + (isArray ? "WriteArray_" : "Write_") + type.Name, + typeof(void), new [] { typeof(SerializationContext), typeof(object) }, + true); + ILGenerator il = dynamicMethod.GetILGenerator(); + + var writer = il.DeclareLocal(typeof(BinaryWriter)); + + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, writerField); + il.Emit(OpCodes.Stloc, writer); // writer = context.writer; + + if (isArray) { + var instance = il.DeclareLocal(type.MakeArrayType()); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Castclass, type.MakeArrayType()); + il.Emit(OpCodes.Stloc, instance); // instance = (type[])arg_1; + + // for (int i = 0; i < instance.Length; i++) write instance[i]; + + var loopStart = il.DefineLabel(); + var loopHead = il.DefineLabel(); + var loopVariable = il.DeclareLocal(typeof(int)); + il.Emit(OpCodes.Ldc_I4_0); + il.Emit(OpCodes.Stloc, loopVariable); // loopVariable = 0 + il.Emit(OpCodes.Br, loopHead); // goto loopHead; + + il.MarkLabel(loopStart); + + if (type.IsEnum || type.IsPrimitive) { + if (type.IsEnum) { + type = type.GetEnumUnderlyingType(); + } + Debug.Assert(type.IsPrimitive); + il.Emit(OpCodes.Ldloc, writer); // writer + il.Emit(OpCodes.Ldloc, instance); // writer, instance + il.Emit(OpCodes.Ldloc, loopVariable); // writer, instance, loopVariable + switch (Type.GetTypeCode(type)) { + case TypeCode.Boolean: + case TypeCode.SByte: + case TypeCode.Byte: + il.Emit(OpCodes.Ldelem_I1); // writer, instance[loopVariable] + il.Emit(callVirt, writeByte); // writer.Write(instance[loopVariable]); + break; + case TypeCode.Char: + case TypeCode.Int16: + case TypeCode.UInt16: + il.Emit(OpCodes.Ldelem_I2); // writer, instance[loopVariable] + il.Emit(callVirt, writeShort); // writer.Write(instance[loopVariable]); + break; + case TypeCode.Int32: + case TypeCode.UInt32: + il.Emit(OpCodes.Ldelem_I4); // writer, instance[loopVariable] + il.Emit(callVirt, writeInt); // writer.Write(instance[loopVariable]); + break; + case TypeCode.Int64: + case TypeCode.UInt64: + il.Emit(OpCodes.Ldelem_I8); // writer, instance[loopVariable] + il.Emit(callVirt, writeLong); // writer.Write(instance[loopVariable]); + break; + case TypeCode.Single: + il.Emit(OpCodes.Ldelem_R4); // writer, instance[loopVariable] + il.Emit(callVirt, writeFloat); // writer.Write(instance[loopVariable]); + break; + case TypeCode.Double: + il.Emit(OpCodes.Ldelem_R8); // writer, instance[loopVariable] + il.Emit(callVirt, writeDouble); // writer.Write(instance[loopVariable]); + break; + default: + throw new NotSupportedException("Unknown primitive type " + type); + } + } else { + il.Emit(OpCodes.Ldloc, instance); // instance + il.Emit(OpCodes.Ldloc, loopVariable); // instance, loopVariable + il.Emit(OpCodes.Ldelem, type); // instance[loopVariable] + EmitWriteValueType(il, writer, type); + } + + il.Emit(OpCodes.Ldloc, loopVariable); // loopVariable + il.Emit(OpCodes.Ldc_I4_1); // loopVariable, 1 + il.Emit(OpCodes.Add); // loopVariable+1 + il.Emit(OpCodes.Stloc, loopVariable); // loopVariable++; + + il.MarkLabel(loopHead); + il.Emit(OpCodes.Ldloc, loopVariable); // loopVariable + il.Emit(OpCodes.Ldloc, instance); // loopVariable, instance + il.Emit(OpCodes.Ldlen); // loopVariable, instance.Length + il.Emit(OpCodes.Conv_I4); + il.Emit(OpCodes.Blt, loopStart); // if (loopVariable < instance.Length) goto loopStart; + } else if (type.IsValueType) { + // boxed value type + if (type.IsEnum || type.IsPrimitive) { + il.Emit(OpCodes.Ldloc, writer); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Unbox_Any, type); + WritePrimitiveValue(il, type); + } else { + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Unbox_Any, type); + EmitWriteValueType(il, writer, type); + } + } else { + // reference type + var instance = il.DeclareLocal(type); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Castclass, type); + il.Emit(OpCodes.Stloc, instance); // instance = (type)arg_1; + + foreach (FieldInfo field in fields) { + EmitWriteField(il, writer, instance, field); // write instance.Field + } + } + il.Emit(OpCodes.Ret); + return (ObjectWriter)dynamicMethod.CreateDelegate(typeof(ObjectWriter)); + } + + /// + /// Emit 'write instance.Field'. + /// Stack transition: ... => ... + /// + void EmitWriteField(ILGenerator il, LocalBuilder writer, LocalBuilder instance, FieldInfo field) + { + Type fieldType = field.FieldType; + if (fieldType.IsValueType) { + if (fieldType.IsPrimitive || fieldType.IsEnum) { + il.Emit(OpCodes.Ldloc, writer); // writer + il.Emit(OpCodes.Ldloc, instance); // writer, instance + il.Emit(OpCodes.Ldfld, field); // writer, instance.field + WritePrimitiveValue(il, fieldType); + } else { + il.Emit(OpCodes.Ldloc, instance); // instance + il.Emit(OpCodes.Ldfld, field); // instance.field + EmitWriteValueType(il, writer, fieldType); + } + } else { + il.Emit(OpCodes.Ldarg_0); // context + il.Emit(OpCodes.Ldloc, instance); // context, instance + il.Emit(OpCodes.Ldfld, field); // context, instance.field + il.Emit(OpCodes.Call, writeObjectID); // context.WriteObjectID(instance.field); + } + } + + /// + /// Writes a primitive value of the specified type. + /// Stack transition: ..., writer, value => ... + /// + void WritePrimitiveValue(ILGenerator il, Type fieldType) + { + if (fieldType.IsEnum) { + fieldType = fieldType.GetEnumUnderlyingType(); + Debug.Assert(fieldType.IsPrimitive); + } + switch (Type.GetTypeCode(fieldType)) { + case TypeCode.Boolean: + case TypeCode.SByte: + case TypeCode.Byte: + il.Emit(callVirt, writeByte); // writer.Write(value); + break; + case TypeCode.Char: + case TypeCode.Int16: + case TypeCode.UInt16: + il.Emit(callVirt, writeShort); // writer.Write(value); + break; + case TypeCode.Int32: + case TypeCode.UInt32: + il.Emit(callVirt, writeInt); // writer.Write(value); + break; + case TypeCode.Int64: + case TypeCode.UInt64: + il.Emit(callVirt, writeLong); // writer.Write(value); + break; + case TypeCode.Single: + il.Emit(callVirt, writeFloat); // writer.Write(value); + break; + case TypeCode.Double: + il.Emit(callVirt, writeDouble); // writer.Write(value); + break; + default: + throw new NotSupportedException("Unknown primitive type " + fieldType); + } + } + + /// + /// Stack transition: ..., value => ... + /// + void EmitWriteValueType(ILGenerator il, LocalBuilder writer, Type valType) + { + Debug.Assert(valType.IsValueType); + Debug.Assert(!(valType.IsEnum || valType.IsPrimitive)); + + var fieldVal = il.DeclareLocal(valType); + il.Emit(OpCodes.Stloc, fieldVal); + + foreach (FieldInfo field in GetSerializableFields(valType)) { + EmitWriteField(il, writer, fieldVal, field); + } + } + #endregion + + StreamingContext streamingContext = new StreamingContext(StreamingContextStates.All); + FormatterConverter formatterConverter = new FormatterConverter(); + + public void Serialize(Stream stream, object instance) + { + Serialize(new BinaryWriterWith7BitEncodedInts(stream), instance); + } + + public void Serialize(BinaryWriter writer, object instance) + { + SerializationContext context = new SerializationContext(this, writer); + context.MarkFixedInstances(this.FixedInstances); + context.Mark(instance); + context.Scan(); + context.ScanTypes(); + context.Write(); + context.WriteObjectID(instance); + } + + delegate void TypeSerializer(object instance, SerializationContext context); + #endregion + + #region Deserialization + sealed class DeserializationContext + { + public Type[] Types; // index: type ID + + public object[] Objects; // index: object ID + + public BinaryReader Reader; + + public object ReadObject() + { + if (this.Objects.Length <= ushort.MaxValue) + return this.Objects[Reader.ReadUInt16()]; + else + return this.Objects[Reader.ReadInt32()]; + } + + #region DeserializeTypeDescriptions + internal int ReadTypeID() + { + if (this.Types.Length <= ushort.MaxValue) + return Reader.ReadUInt16(); + else + return Reader.ReadInt32(); + } + + internal void DeserializeTypeDescriptions() + { + for (int i = 0; i < this.Types.Length; i++) { + Type type = this.Types[i]; + if (type.IsGenericTypeDefinition || type.HasElementType) + continue; + int versionNumber = Reader.ReadInt32(); + if (versionNumber != FastSerializerVersionAttribute.GetVersionNumber(type)) + throw new SerializationException("Type '" + type.FullName + "' was serialized with version " + versionNumber + ", but is version " + FastSerializerVersionAttribute.GetVersionNumber(type)); + + bool isCustomSerialization = typeof(ISerializable).IsAssignableFrom(type); + bool typeIsSpecial = type.IsPrimitive || isCustomSerialization; + + byte serializedFieldCount = Reader.ReadByte(); + if (serializedFieldCount == byte.MaxValue) { + // special type + if (!typeIsSpecial) + throw new SerializationException("Type '" + type.FullName + "' was serialized as special type, but isn't special now."); + } else { + if (typeIsSpecial) + throw new SerializationException("Type '" + type.FullName + "' wasn't serialized as special type, but is special now."); + + var availableFields = GetSerializableFields(this.Types[i]); + if (availableFields.Count != serializedFieldCount) + throw new SerializationException("Number of fields on " + type.FullName + " has changed."); + for (int j = 0; j < serializedFieldCount; j++) { + int fieldTypeID = ReadTypeID(); + + string fieldName = Reader.ReadString(); + FieldInfo fieldInfo = availableFields[j]; + if (fieldInfo.Name != fieldName) + throw new SerializationException("Field mismatch on type " + type.FullName); + if (fieldInfo.FieldType != this.Types[fieldTypeID]) + throw new SerializationException(type.FullName + "." + fieldName + " was serialized as " + this.Types[fieldTypeID] + ", but now is " + fieldInfo.FieldType); + } + } + } + } + #endregion + } + + delegate void ObjectReader(DeserializationContext context, object instance); + + public object Deserialize(Stream stream) + { + return Deserialize(new BinaryReaderWith7BitEncodedInts(stream)); + } + + public object Deserialize(BinaryReader reader) + { + if (reader.ReadInt32() != magic) + throw new SerializationException("The data cannot be read by FastSerializer (unknown magic value)"); + + DeserializationContext context = new DeserializationContext(); + context.Reader = reader; + context.Objects = new object[reader.ReadInt32()]; + context.Types = new Type[reader.ReadInt32()]; + string[] assemblyNames = new string[reader.ReadInt32()]; + int fixedInstanceCount = reader.ReadInt32(); + + if (fixedInstanceCount != 0) { + if (this.FixedInstances == null || this.FixedInstances.Length != fixedInstanceCount) + throw new SerializationException("Number of fixed instances doesn't match"); + for (int i = 0; i < fixedInstanceCount; i++) { + context.Objects[i + 1] = this.FixedInstances[i]; + } + } + + for (int i = 0; i < assemblyNames.Length; i++) { + assemblyNames[i] = reader.ReadString(); + } + int stringTypeID = -1; + for (int i = 0; i < context.Types.Length; i++) { + byte typeKind = reader.ReadByte(); + switch (typeKind) { + case Type_ReferenceType: + case Type_ValueType: + int assemblyID; + if (assemblyNames.Length <= ushort.MaxValue) + assemblyID = reader.ReadUInt16(); + else + assemblyID = reader.ReadInt32(); + string assemblyName = assemblyNames[assemblyID]; + string typeName = reader.ReadString(); + Type type; + if (SerializationBinder != null) { + type = SerializationBinder.BindToType(assemblyName, typeName); + } else { + type = Assembly.Load(assemblyName).GetType(typeName); + } + if (type == null) + throw new SerializationException("Could not find '" + typeName + "' in '" + assemblyName + "'"); + if (typeKind == Type_ValueType && !type.IsValueType) + throw new SerializationException("Expected '" + typeName + "' to be a value type, but it is reference type"); + if (typeKind == Type_ReferenceType && type.IsValueType) + throw new SerializationException("Expected '" + typeName + "' to be a reference type, but it is value type"); + context.Types[i] = type; + if (type == typeof(string)) + stringTypeID = i; + break; + case Type_SZArray: + context.Types[i] = context.Types[context.ReadTypeID()].MakeArrayType(); + break; + case Type_ParameterizedType: + Type genericType = context.Types[context.ReadTypeID()]; + int typeParameterCount = genericType.GetGenericArguments().Length; + Type[] typeArguments = new Type[typeParameterCount]; + for (int j = 0; j < typeArguments.Length; j++) { + typeArguments[j] = context.Types[context.ReadTypeID()]; + } + context.Types[i] = genericType.MakeGenericType(typeArguments); + break; + default: + throw new SerializationException("Unknown type kind"); + } + } + context.DeserializeTypeDescriptions(); + int[] typeIDByObjectID = new int[context.Objects.Length]; + for (int i = 1 + fixedInstanceCount; i < context.Objects.Length; i++) { + int typeID = context.ReadTypeID(); + + object instance; + if (typeID == stringTypeID) { + instance = reader.ReadString(); + } else { + Type type = context.Types[typeID]; + if (type.IsArray) { + int length = reader.ReadInt32(); + instance = Array.CreateInstance(type.GetElementType(), length); + } else { + instance = FormatterServices.GetUninitializedObject(type); + } + } + context.Objects[i] = instance; + typeIDByObjectID[i] = typeID; + } + List customDeserializatons = new List(); + ObjectReader[] objectReaders = new ObjectReader[context.Types.Length]; // index: type ID + for (int i = 1 + fixedInstanceCount; i < context.Objects.Length; i++) { + object instance = context.Objects[i]; + int typeID = typeIDByObjectID[i]; + Log("0x{2:x6} Read #{0}: {1}", i, context.Types[typeID].Name, reader.BaseStream.Position); + ISerializable serializable = instance as ISerializable; + if (serializable != null) { + Type type = context.Types[typeID]; + SerializationInfo info = new SerializationInfo(type, formatterConverter); + int count = reader.ReadInt32(); + for (int j = 0; j < count; j++) { + string name = reader.ReadString(); + object val = context.ReadObject(); + info.AddValue(name, val); + } + CustomDeserializationAction action = GetCustomDeserializationAction(type); + customDeserializatons.Add(new CustomDeserialization(instance, info, action)); + } else { + ObjectReader objectReader = objectReaders[typeID]; + if (objectReader == null) { + objectReader = GetReader(context.Types[typeID]); + objectReaders[typeID] = objectReader; + } + objectReader(context, instance); + } + } + Log("File was read successfully, now running {0} custom deserializations...", customDeserializatons.Count); + foreach (CustomDeserialization customDeserializaton in customDeserializatons) { + customDeserializaton.Run(streamingContext); + } + for (int i = 1 + fixedInstanceCount; i < context.Objects.Length; i++) { + IDeserializationCallback dc = context.Objects[i] as IDeserializationCallback; + if (dc != null) + dc.OnDeserialization(null); + } + + return context.ReadObject(); + } + + #region Object Reader + static readonly FieldInfo readerField = typeof(DeserializationContext).GetField("Reader"); + static readonly MethodInfo readObject = typeof(DeserializationContext).GetMethod("ReadObject"); + + static readonly MethodInfo readByte = typeof(BinaryReader).GetMethod("ReadByte"); + static readonly MethodInfo readShort = typeof(BinaryReader).GetMethod("ReadInt16"); + static readonly MethodInfo readInt = typeof(BinaryReader).GetMethod("ReadInt32"); + static readonly MethodInfo readLong = typeof(BinaryReader).GetMethod("ReadInt64"); + static readonly MethodInfo readFloat = typeof(BinaryReader).GetMethod("ReadSingle"); + static readonly MethodInfo readDouble = typeof(BinaryReader).GetMethod("ReadDouble"); + + Dictionary readers = new Dictionary(); + + ObjectReader GetReader(Type type) + { + ObjectReader reader; + if (!readers.TryGetValue(type, out reader)) { + reader = CreateReader(type); + readers.Add(type, reader); + } + return reader; + } + + ObjectReader CreateReader(Type type) + { + if (type == typeof(string)) { + // String contents are written in the object creation section, + // not into the field value section; so there's nothing to read here. + return delegate {}; + } + bool isArray = type.IsArray; + if (isArray) { + if (type.GetArrayRank() != 1) + throw new NotSupportedException(); + type = type.GetElementType(); + if (!type.IsValueType) { + return delegate (DeserializationContext context, object arrayInstance) { + object[] array = (object[])arrayInstance; + for (int i = 0; i < array.Length; i++) { + array[i] = context.ReadObject(); + } + }; + } else if (type == typeof(byte)) { + return delegate (DeserializationContext context, object arrayInstance) { + byte[] array = (byte[])arrayInstance; + BinaryReader binaryReader = context.Reader; + int pos = 0; + int bytesRead; + do { + bytesRead = binaryReader.Read(array, pos, array.Length - pos); + pos += bytesRead; + } while (bytesRead > 0); + if (pos != array.Length) + throw new EndOfStreamException(); + }; + } + } + var fields = GetSerializableFields(type); + if (fields.Count == 0) { + // The reader has nothing to do for this object. + return delegate { }; + } + + DynamicMethod dynamicMethod = new DynamicMethod( + (isArray ? "ReadArray_" : "Read_") + type.Name, + MethodAttributes.Public | MethodAttributes.Static, + CallingConventions.Standard, + typeof(void), new [] { typeof(DeserializationContext), typeof(object) }, + type, + true); + ILGenerator il = dynamicMethod.GetILGenerator(); + + var reader = il.DeclareLocal(typeof(BinaryReader)); + + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, readerField); + il.Emit(OpCodes.Stloc, reader); // reader = context.reader; + + if (isArray) { + var instance = il.DeclareLocal(type.MakeArrayType()); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Castclass, type.MakeArrayType()); + il.Emit(OpCodes.Stloc, instance); // instance = (type[])arg_1; + + // for (int i = 0; i < instance.Length; i++) read &instance[i]; + + var loopStart = il.DefineLabel(); + var loopHead = il.DefineLabel(); + var loopVariable = il.DeclareLocal(typeof(int)); + il.Emit(OpCodes.Ldc_I4_0); + il.Emit(OpCodes.Stloc, loopVariable); // loopVariable = 0 + il.Emit(OpCodes.Br, loopHead); // goto loopHead; + + il.MarkLabel(loopStart); + + if (type.IsEnum || type.IsPrimitive) { + if (type.IsEnum) { + type = type.GetEnumUnderlyingType(); + } + Debug.Assert(type.IsPrimitive); + il.Emit(OpCodes.Ldloc, instance); // instance + il.Emit(OpCodes.Ldloc, loopVariable); // instance, loopVariable + ReadPrimitiveValue(il, reader, type); // instance, loopVariable, value + switch (Type.GetTypeCode(type)) { + case TypeCode.Boolean: + case TypeCode.SByte: + case TypeCode.Byte: + il.Emit(OpCodes.Stelem_I1); // instance[loopVariable] = value; + break; + case TypeCode.Char: + case TypeCode.Int16: + case TypeCode.UInt16: + il.Emit(OpCodes.Stelem_I2); // instance[loopVariable] = value; + break; + case TypeCode.Int32: + case TypeCode.UInt32: + il.Emit(OpCodes.Stelem_I4); // instance[loopVariable] = value; + break; + case TypeCode.Int64: + case TypeCode.UInt64: + il.Emit(OpCodes.Stelem_I8); // instance[loopVariable] = value; + break; + case TypeCode.Single: + il.Emit(OpCodes.Stelem_R4); // instance[loopVariable] = value; + break; + case TypeCode.Double: + il.Emit(OpCodes.Stelem_R8); // instance[loopVariable] = value; + break; + default: + throw new NotSupportedException("Unknown primitive type " + type); + } + } else { + il.Emit(OpCodes.Ldloc, instance); // instance + il.Emit(OpCodes.Ldloc, loopVariable); // instance, loopVariable + il.Emit(OpCodes.Ldelema, type); // instance[loopVariable] + EmitReadValueType(il, reader, type); + } + + il.Emit(OpCodes.Ldloc, loopVariable); // loopVariable + il.Emit(OpCodes.Ldc_I4_1); // loopVariable, 1 + il.Emit(OpCodes.Add); // loopVariable+1 + il.Emit(OpCodes.Stloc, loopVariable); // loopVariable++; + + il.MarkLabel(loopHead); + il.Emit(OpCodes.Ldloc, loopVariable); // loopVariable + il.Emit(OpCodes.Ldloc, instance); // loopVariable, instance + il.Emit(OpCodes.Ldlen); // loopVariable, instance.Length + il.Emit(OpCodes.Conv_I4); + il.Emit(OpCodes.Blt, loopStart); // if (loopVariable < instance.Length) goto loopStart; + } else if (type.IsValueType) { + // boxed value type + il.Emit(OpCodes.Ldarg_1); // instance + il.Emit(OpCodes.Unbox, type); // &(Type)instance + if (type.IsEnum || type.IsPrimitive) { + if (type.IsEnum) { + type = type.GetEnumUnderlyingType(); + } + Debug.Assert(type.IsPrimitive); + ReadPrimitiveValue(il, reader, type); // &(Type)instance, value + switch (Type.GetTypeCode(type)) { + case TypeCode.Boolean: + case TypeCode.SByte: + case TypeCode.Byte: + il.Emit(OpCodes.Stind_I1); + break; + case TypeCode.Char: + case TypeCode.Int16: + case TypeCode.UInt16: + il.Emit(OpCodes.Stind_I2); + break; + case TypeCode.Int32: + case TypeCode.UInt32: + il.Emit(OpCodes.Stind_I4); + break; + case TypeCode.Int64: + case TypeCode.UInt64: + il.Emit(OpCodes.Stind_I8); + break; + case TypeCode.Single: + il.Emit(OpCodes.Stind_R4); + break; + case TypeCode.Double: + il.Emit(OpCodes.Stind_R8); + break; + default: + throw new NotSupportedException("Unknown primitive type " + type); + } + } else { + EmitReadValueType(il, reader, type); + } + } else { + // reference type + var instance = il.DeclareLocal(type); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Castclass, type); + il.Emit(OpCodes.Stloc, instance); // instance = (type)arg_1; + + foreach (FieldInfo field in fields) { + EmitReadField(il, reader, instance, field); // read instance.Field + } + } + il.Emit(OpCodes.Ret); + return (ObjectReader)dynamicMethod.CreateDelegate(typeof(ObjectReader)); + } + + void EmitReadField(ILGenerator il, LocalBuilder reader, LocalBuilder instance, FieldInfo field) + { + Type fieldType = field.FieldType; + if (fieldType.IsValueType) { + if (fieldType.IsPrimitive || fieldType.IsEnum) { + il.Emit(OpCodes.Ldloc, instance); // instance + ReadPrimitiveValue(il, reader, fieldType); // instance, value + il.Emit(OpCodes.Stfld, field); // instance.field = value; + } else { + il.Emit(OpCodes.Ldloc, instance); // instance + il.Emit(OpCodes.Ldflda, field); // &instance.field + EmitReadValueType(il, reader, fieldType); + } + } else { + il.Emit(OpCodes.Ldloc, instance); // instance + il.Emit(OpCodes.Ldarg_0); // instance, context + il.Emit(OpCodes.Call, readObject); // instance, context.ReadObject() + il.Emit(OpCodes.Castclass, fieldType); + il.Emit(OpCodes.Stfld, field); // instance.field = (fieldType) context.ReadObject(); + } + } + + /// + /// Reads a primitive value of the specified type. + /// Stack transition: ... => ..., value + /// + void ReadPrimitiveValue(ILGenerator il, LocalBuilder reader, Type fieldType) + { + if (fieldType.IsEnum) { + fieldType = fieldType.GetEnumUnderlyingType(); + Debug.Assert(fieldType.IsPrimitive); + } + il.Emit(OpCodes.Ldloc, reader); + switch (Type.GetTypeCode(fieldType)) { + case TypeCode.Boolean: + case TypeCode.SByte: + case TypeCode.Byte: + il.Emit(callVirt, readByte); + break; + case TypeCode.Char: + case TypeCode.Int16: + case TypeCode.UInt16: + il.Emit(callVirt, readShort); + break; + case TypeCode.Int32: + case TypeCode.UInt32: + il.Emit(callVirt, readInt); + break; + case TypeCode.Int64: + case TypeCode.UInt64: + il.Emit(callVirt, readLong); + break; + case TypeCode.Single: + il.Emit(callVirt, readFloat); + break; + case TypeCode.Double: + il.Emit(callVirt, readDouble); + break; + default: + throw new NotSupportedException("Unknown primitive type " + fieldType); + } + } + + /// + /// Stack transition: ..., field-ref => ... + /// + void EmitReadValueType(ILGenerator il, LocalBuilder reader, Type valType) + { + Debug.Assert(valType.IsValueType); + Debug.Assert(!(valType.IsEnum || valType.IsPrimitive)); + + var fieldRef = il.DeclareLocal(valType.MakeByRefType()); + il.Emit(OpCodes.Stloc, fieldRef); + + foreach (FieldInfo field in GetSerializableFields(valType)) { + EmitReadField(il, reader, fieldRef, field); + } + } + #endregion + + #region Custom Deserialization + struct CustomDeserialization + { + readonly object instance; + readonly SerializationInfo serializationInfo; + readonly CustomDeserializationAction action; + + public CustomDeserialization(object instance, SerializationInfo serializationInfo, CustomDeserializationAction action) + { + this.instance = instance; + this.serializationInfo = serializationInfo; + this.action = action; + } + + public void Run(StreamingContext context) + { + action(instance, serializationInfo, context); + } + } + + delegate void CustomDeserializationAction(object instance, SerializationInfo info, StreamingContext context); + + Dictionary customDeserializationActions = new Dictionary(); + + CustomDeserializationAction GetCustomDeserializationAction(Type type) + { + CustomDeserializationAction action; + if (!customDeserializationActions.TryGetValue(type, out action)) { + action = CreateCustomDeserializationAction(type); + customDeserializationActions.Add(type, action); + } + return action; + } + + static CustomDeserializationAction CreateCustomDeserializationAction(Type type) + { + ConstructorInfo ctor = type.GetConstructor( + BindingFlags.DeclaredOnly | BindingFlags.ExactBinding | BindingFlags.Instance + | BindingFlags.NonPublic | BindingFlags.Public, + null, + new Type [] { typeof(SerializationInfo), typeof(StreamingContext) }, + null); + if (ctor == null) + throw new SerializationException("Could not find deserialization constructor for " + type.FullName); + + DynamicMethod dynamicMethod = new DynamicMethod( + "CallCtor_" + type.Name, + MethodAttributes.Public | MethodAttributes.Static, + CallingConventions.Standard, + typeof(void), new [] { typeof(object), typeof(SerializationInfo), typeof(StreamingContext) }, + type, + true); + ILGenerator il = dynamicMethod.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldarg_2); + il.Emit(OpCodes.Call, ctor); + il.Emit(OpCodes.Ret); + return (CustomDeserializationAction)dynamicMethod.CreateDelegate(typeof(CustomDeserializationAction)); + } + #endregion + #endregion + + [Conditional("DEBUG_SERIALIZER")] + static void Log(string format, params object[] args) + { + Debug.WriteLine(format, args); + } + } + + /// + /// Specifies the version of the class. + /// The will refuse to deserialize an instance that was stored by + /// a different version of the class than the current one. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum)] + public class FastSerializerVersionAttribute : Attribute + { + readonly int versionNumber; + + public FastSerializerVersionAttribute(int versionNumber) + { + this.versionNumber = versionNumber; + } + + public int VersionNumber { + get { + return versionNumber; + } + } + + internal static int GetVersionNumber(Type type) + { + var arr = type.GetCustomAttributes(typeof(FastSerializerVersionAttribute), false); + if (arr.Length == 0) + return 0; + else + return ((FastSerializerVersionAttribute)arr[0]).VersionNumber; + } + } +} diff --git a/ICSharpCode.Decompiler/Util/ImmutableStack.cs b/ICSharpCode.Decompiler/Util/ImmutableStack.cs new file mode 100644 index 000000000..9738ddc33 --- /dev/null +++ b/ICSharpCode.Decompiler/Util/ImmutableStack.cs @@ -0,0 +1,132 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Diagnostics; +using System.Text; + +namespace ICSharpCode.NRefactory.Utils +{ + /// + /// An immutable stack. + /// + /// Using 'foreach' on the stack will return the items from top to bottom (in the order they would be popped). + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")] + [Serializable] + public sealed class ImmutableStack : IEnumerable + { + /// + /// Gets the empty stack instance. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "ImmutableStack is immutable")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")] + public static readonly ImmutableStack Empty = new ImmutableStack(); + + readonly T value; + readonly ImmutableStack next; + + private ImmutableStack() + { + } + + private ImmutableStack(T value, ImmutableStack next) + { + this.value = value; + this.next = next; + } + + /// + /// Pushes an item on the stack. This does not modify the stack itself, but returns a new + /// one with the value pushed. + /// + public ImmutableStack Push(T item) + { + return new ImmutableStack(item, this); + } + + /// + /// Gets the item on the top of the stack. + /// + /// The stack is empty. + public T Peek() + { + if (IsEmpty) + throw new InvalidOperationException("Operation not valid on empty stack."); + return value; + } + + /// + /// Gets the item on the top of the stack. + /// Returns default(T) if the stack is empty. + /// + public T PeekOrDefault() + { + return value; + } + + /// + /// Gets the stack with the top item removed. + /// + /// The stack is empty. + public ImmutableStack Pop() + { + if (IsEmpty) + throw new InvalidOperationException("Operation not valid on empty stack."); + return next; + } + + /// + /// Gets if this stack is empty. + /// + public bool IsEmpty { + get { return next == null; } + } + + /// + /// Gets an enumerator that iterates through the stack top-to-bottom. + /// + public IEnumerator GetEnumerator() + { + ImmutableStack t = this; + while (!t.IsEmpty) { + yield return t.value; + t = t.next; + } + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + /// + public override string ToString() + { + StringBuilder b = new StringBuilder("[Stack"); + foreach (T val in this) { + b.Append(' '); + b.Append(val); + } + b.Append(']'); + return b.ToString(); + } + } +} diff --git a/ICSharpCode.Decompiler/Util/LazyInit.cs b/ICSharpCode.Decompiler/Util/LazyInit.cs new file mode 100644 index 000000000..3483e53f4 --- /dev/null +++ b/ICSharpCode.Decompiler/Util/LazyInit.cs @@ -0,0 +1,48 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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.Threading; + +namespace ICSharpCode.NRefactory.Utils +{ + public static class LazyInit + { + public static T VolatileRead(ref T location) where T : class + { + #if NET_4_5 + return Volatile.Read(ref location); + #else + T result = location; + Thread.MemoryBarrier(); + return result; + #endif + } + + /// + /// Atomically performs the following operation: + /// - If target is null: stores newValue in target and returns newValue. + /// - If target is not null: returns target. + /// + public static T GetOrSet(ref T target, T newValue) where T : class + { + T oldValue = Interlocked.CompareExchange(ref target, newValue, null); + return oldValue ?? newValue; + } + } +} diff --git a/ICSharpCode.Decompiler/Util/MultiDictionary.cs b/ICSharpCode.Decompiler/Util/MultiDictionary.cs new file mode 100644 index 000000000..261537601 --- /dev/null +++ b/ICSharpCode.Decompiler/Util/MultiDictionary.cs @@ -0,0 +1,154 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Linq; + +namespace ICSharpCode.NRefactory.Utils +{ + /// + /// A dictionary that allows multiple pairs with the same key. + /// + public class MultiDictionary : ILookup + { + readonly Dictionary> dict; + + public MultiDictionary() + { + dict = new Dictionary>(); + } + + public MultiDictionary(IEqualityComparer comparer) + { + dict = new Dictionary>(comparer); + } + + public void Add(TKey key, TValue value) + { + List valueList; + if (!dict.TryGetValue(key, out valueList)) { + valueList = new List(); + dict.Add(key, valueList); + } + valueList.Add(value); + } + + public bool Remove(TKey key, TValue value) + { + List valueList; + if (dict.TryGetValue(key, out valueList)) { + if (valueList.Remove(value)) { + if (valueList.Count == 0) + dict.Remove(key); + return true; + } + } + return false; + } + + /// + /// Removes all entries with the specified key. + /// + /// Returns true if at least one entry was removed. + public bool RemoveAll(TKey key) + { + return dict.Remove(key); + } + + public void Clear() + { + dict.Clear(); + } + + #if NET_4_5 + public IReadOnlyList this[TKey key] { + #else + public IList this[TKey key] { + #endif + get { + List list; + if (dict.TryGetValue(key, out list)) + return list; + else + return EmptyList.Instance; + } + } + + /// + /// Returns the number of different keys. + /// + public int Count { + get { return dict.Count; } + } + + public ICollection Keys { + get { return dict.Keys; } + } + + public IEnumerable Values { + get { return dict.Values.SelectMany(list => list); } + } + + IEnumerable ILookup.this[TKey key] { + get { return this[key]; } + } + + bool ILookup.Contains(TKey key) + { + return dict.ContainsKey(key); + } + + public IEnumerator> GetEnumerator() + { + foreach (var pair in dict) + yield return new Grouping(pair.Key, pair.Value); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + sealed class Grouping : IGrouping + { + readonly TKey key; + readonly List values; + + public Grouping(TKey key, List values) + { + this.key = key; + this.values = values; + } + + public TKey Key { + get { return key; } + } + + public IEnumerator GetEnumerator() + { + return values.GetEnumerator(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return values.GetEnumerator(); + } + } + } +} diff --git a/ICSharpCode.Decompiler/Util/Platform.cs b/ICSharpCode.Decompiler/Util/Platform.cs new file mode 100644 index 000000000..383d8f11a --- /dev/null +++ b/ICSharpCode.Decompiler/Util/Platform.cs @@ -0,0 +1,40 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.Utils +{ + /// + /// Platform-specific code. + /// + public static class Platform + { + public static StringComparer FileNameComparer { + get { + switch (Environment.OSVersion.Platform) { + case PlatformID.Unix: + case PlatformID.MacOSX: + return StringComparer.Ordinal; + default: + return StringComparer.OrdinalIgnoreCase; + } + } + } + } +} diff --git a/ICSharpCode.Decompiler/Util/ProjectedList.cs b/ICSharpCode.Decompiler/Util/ProjectedList.cs new file mode 100644 index 000000000..8b0ae69b8 --- /dev/null +++ b/ICSharpCode.Decompiler/Util/ProjectedList.cs @@ -0,0 +1,239 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.Utils +{ + public sealed class ProjectedList : IList where TOutput : class + { + readonly IList input; + readonly Func projection; + readonly TOutput[] items; + + public ProjectedList(IList input, Func projection) + { + if (input == null) + throw new ArgumentNullException("input"); + if (projection == null) + throw new ArgumentNullException("projection"); + this.input = input; + this.projection = projection; + this.items = new TOutput[input.Count]; + } + + public TOutput this[int index] { + get { + TOutput output = LazyInit.VolatileRead(ref items[index]); + if (output != null) { + return output; + } + return LazyInit.GetOrSet(ref items[index], projection(input[index])); + } + } + + TOutput IList.this[int index] { + get { return this[index]; } + set { + throw new NotSupportedException(); + } + } + + public int Count { + get { return items.Length; } + } + + bool ICollection.IsReadOnly { + get { return true; } + } + + int IList.IndexOf(TOutput item) + { + var comparer = EqualityComparer.Default; + for (int i = 0; i < this.Count; i++) { + if (comparer.Equals(this[i], item)) + return i; + } + return -1; + } + + void IList.Insert(int index, TOutput item) + { + throw new NotSupportedException(); + } + + void IList.RemoveAt(int index) + { + throw new NotSupportedException(); + } + + void ICollection.Add(TOutput item) + { + throw new NotSupportedException(); + } + + void ICollection.Clear() + { + throw new NotSupportedException(); + } + + bool ICollection.Contains(TOutput item) + { + var comparer = EqualityComparer.Default; + for (int i = 0; i < this.Count; i++) { + if (comparer.Equals(this[i], item)) + return true; + } + return false; + } + + void ICollection.CopyTo(TOutput[] array, int arrayIndex) + { + for (int i = 0; i < items.Length; i++) { + array[arrayIndex + i] = this[i]; + } + } + + bool ICollection.Remove(TOutput item) + { + throw new NotSupportedException(); + } + + public IEnumerator GetEnumerator() + { + for (int i = 0; i < this.Count; i++) { + yield return this[i]; + } + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + + public sealed class ProjectedList : IList where TOutput : class + { + readonly IList input; + readonly TContext context; + readonly Func projection; + readonly TOutput[] items; + + public ProjectedList(TContext context, IList input, Func projection) + { + if (input == null) + throw new ArgumentNullException("input"); + if (projection == null) + throw new ArgumentNullException("projection"); + this.input = input; + this.context = context; + this.projection = projection; + this.items = new TOutput[input.Count]; + } + + public TOutput this[int index] { + get { + TOutput output = LazyInit.VolatileRead(ref items[index]); + if (output != null) { + return output; + } + return LazyInit.GetOrSet(ref items[index], projection(context, input[index])); + } + } + + TOutput IList.this[int index] { + get { return this[index]; } + set { + throw new NotSupportedException(); + } + } + + public int Count { + get { return items.Length; } + } + + bool ICollection.IsReadOnly { + get { return true; } + } + + int IList.IndexOf(TOutput item) + { + var comparer = EqualityComparer.Default; + for (int i = 0; i < this.Count; i++) { + if (comparer.Equals(this[i], item)) + return i; + } + return -1; + } + + void IList.Insert(int index, TOutput item) + { + throw new NotSupportedException(); + } + + void IList.RemoveAt(int index) + { + throw new NotSupportedException(); + } + + void ICollection.Add(TOutput item) + { + throw new NotSupportedException(); + } + + void ICollection.Clear() + { + throw new NotSupportedException(); + } + + bool ICollection.Contains(TOutput item) + { + var comparer = EqualityComparer.Default; + for (int i = 0; i < this.Count; i++) { + if (comparer.Equals(this[i], item)) + return true; + } + return false; + } + + void ICollection.CopyTo(TOutput[] array, int arrayIndex) + { + for (int i = 0; i < items.Length; i++) { + array[arrayIndex + i] = this[i]; + } + } + + bool ICollection.Remove(TOutput item) + { + throw new NotSupportedException(); + } + + public IEnumerator GetEnumerator() + { + for (int i = 0; i < this.Count; i++) { + yield return this[i]; + } + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff --git a/ICSharpCode.Decompiler/Util/ReferenceComparer.cs b/ICSharpCode.Decompiler/Util/ReferenceComparer.cs new file mode 100644 index 000000000..d87709c69 --- /dev/null +++ b/ICSharpCode.Decompiler/Util/ReferenceComparer.cs @@ -0,0 +1,39 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// 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 System.Runtime.CompilerServices; + +namespace ICSharpCode.NRefactory.Utils +{ + public sealed class ReferenceComparer : IEqualityComparer + { + public readonly static ReferenceComparer Instance = new ReferenceComparer(); + + public new bool Equals(object x, object y) + { + return x == y; + } + + public int GetHashCode(object obj) + { + return RuntimeHelpers.GetHashCode(obj); + } + } +} diff --git a/ICSharpCode.Decompiler/Util/TreeTraversal.cs b/ICSharpCode.Decompiler/Util/TreeTraversal.cs new file mode 100644 index 000000000..23f0bcb9f --- /dev/null +++ b/ICSharpCode.Decompiler/Util/TreeTraversal.cs @@ -0,0 +1,112 @@ +// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.Utils +{ + /// + /// Static helper methods for traversing trees. + /// + public static class TreeTraversal + { + /// + /// Converts a tree data structure into a flat list by traversing it in pre-order. + /// + /// The root element of the tree. + /// The function that gets the children of an element. + /// Iterator that enumerates the tree structure in pre-order. + public static IEnumerable PreOrder(T root, Func> recursion) + { + return PreOrder(new T[] { root }, recursion); + } + + /// + /// Converts a tree data structure into a flat list by traversing it in pre-order. + /// + /// The root elements of the forest. + /// The function that gets the children of an element. + /// Iterator that enumerates the tree structure in pre-order. + public static IEnumerable PreOrder(IEnumerable input, Func> recursion) + { + Stack> stack = new Stack>(); + try { + stack.Push(input.GetEnumerator()); + while (stack.Count > 0) { + while (stack.Peek().MoveNext()) { + T element = stack.Peek().Current; + yield return element; + IEnumerable children = recursion(element); + if (children != null) { + stack.Push(children.GetEnumerator()); + } + } + stack.Pop().Dispose(); + } + } finally { + while (stack.Count > 0) { + stack.Pop().Dispose(); + } + } + } + + /// + /// Converts a tree data structure into a flat list by traversing it in post-order. + /// + /// The root element of the tree. + /// The function that gets the children of an element. + /// Iterator that enumerates the tree structure in post-order. + public static IEnumerable PostOrder(T root, Func> recursion) + { + return PostOrder(new T[] { root }, recursion); + } + + /// + /// Converts a tree data structure into a flat list by traversing it in post-order. + /// + /// The root elements of the forest. + /// The function that gets the children of an element. + /// Iterator that enumerates the tree structure in post-order. + public static IEnumerable PostOrder(IEnumerable input, Func> recursion) + { + Stack> stack = new Stack>(); + try { + stack.Push(input.GetEnumerator()); + while (stack.Count > 0) { + while (stack.Peek().MoveNext()) { + T element = stack.Peek().Current; + IEnumerable children = recursion(element); + if (children != null) { + stack.Push(children.GetEnumerator()); + } else { + yield return element; + } + } + stack.Pop().Dispose(); + if (stack.Count > 0) + yield return stack.Peek().Current; + } + } finally { + while (stack.Count > 0) { + stack.Pop().Dispose(); + } + } + } + } +} diff --git a/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj b/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj index 57908ae7d..ca39df548 100644 --- a/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj +++ b/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj @@ -131,10 +131,6 @@ Mono.Cecil False - - {3b2a5653-ec97-4001-bb9b-d90f1af2c371} - ICSharpCode.NRefactory - {dde2a481-8271-4eac-a330-8fa6a38d13d1} ICSharpCode.TreeView diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index cdd76b823..94a99fbfb 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -414,10 +414,6 @@ {984cc812-9470-4a13-aff9-cc44068d666c} ICSharpCode.Decompiler - - {3b2a5653-ec97-4001-bb9b-d90f1af2c371} - ICSharpCode.NRefactory - {dde2a481-8271-4eac-a330-8fa6a38d13d1} ICSharpCode.TreeView