Browse Source

merge conflicts to update with latest branch

pull/943/head
Chris Johnston 7 years ago
parent
commit
2290a62235
100 changed files with 359 additions and 47 deletions
  1. +113
    -0
      .editorconfig
  2. +44
    -0
      CONTRIBUTING.md
  3. +16
    -16
      Discord.Net.sln
  4. +2
    -2
      Discord.Net.targets
  5. +2
    -2
      README.md
  6. +2
    -2
      appveyor.yml
  7. +3
    -3
      docs/guides/commands/commands.md
  8. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/AuthenticateParams.cs
  9. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/AuthenticateResponse.cs
  10. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/AuthorizeParams.cs
  11. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/AuthorizeResponse.cs
  12. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/Channel.cs
  13. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/ChannelSubscriptionParams.cs
  14. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/ChannelSummary.cs
  15. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/ErrorEvent.cs
  16. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/ExtendedVoiceState.cs
  17. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/GetChannelParams.cs
  18. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/GetChannelsParams.cs
  19. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/GetChannelsResponse.cs
  20. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/GetGuildParams.cs
  21. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/GetGuildsParams.cs
  22. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/GetGuildsResponse.cs
  23. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/Guild.cs
  24. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/GuildMember.cs
  25. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/GuildStatusEvent.cs
  26. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/GuildSubscriptionParams.cs
  27. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/GuildSummary.cs
  28. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/Message.cs
  29. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/MessageEvent.cs
  30. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/Pan.cs
  31. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/ReadyEvent.cs
  32. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/RpcConfig.cs
  33. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/SelectChannelParams.cs
  34. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/SetLocalVolumeParams.cs
  35. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/SetLocalVolumeResponse.cs
  36. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/SpeakingEvent.cs
  37. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/SubscriptionResponse.cs
  38. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/UserVoiceSettings.cs
  39. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/VoiceDevice.cs
  40. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/VoiceDeviceSettings.cs
  41. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/VoiceMode.cs
  42. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/VoiceSettings.cs
  43. +0
    -0
      experiment/Discord.Net.Rpc/API/Rpc/VoiceShortcut.cs
  44. +0
    -0
      experiment/Discord.Net.Rpc/API/RpcFrame.cs
  45. +0
    -0
      experiment/Discord.Net.Rpc/AssemblyInfo.cs
  46. +0
    -0
      experiment/Discord.Net.Rpc/Commands/RpcCommandContext.cs
  47. +0
    -0
      experiment/Discord.Net.Rpc/Discord.Net.Rpc.csproj
  48. +0
    -0
      experiment/Discord.Net.Rpc/DiscordRpcApiClient.cs
  49. +0
    -0
      experiment/Discord.Net.Rpc/DiscordRpcClient.Events.cs
  50. +0
    -0
      experiment/Discord.Net.Rpc/DiscordRpcClient.cs
  51. +0
    -0
      experiment/Discord.Net.Rpc/DiscordRpcConfig.cs
  52. +0
    -0
      experiment/Discord.Net.Rpc/Entities/Channels/IRpcAudioChannel.cs
  53. +0
    -0
      experiment/Discord.Net.Rpc/Entities/Channels/IRpcMessageChannel.cs
  54. +0
    -0
      experiment/Discord.Net.Rpc/Entities/Channels/IRpcPrivateChannel.cs
  55. +0
    -0
      experiment/Discord.Net.Rpc/Entities/Channels/RpcChannel.cs
  56. +0
    -0
      experiment/Discord.Net.Rpc/Entities/Channels/RpcChannelSummary.cs
  57. +0
    -0
      experiment/Discord.Net.Rpc/Entities/Channels/RpcDMChannel.cs
  58. +0
    -0
      experiment/Discord.Net.Rpc/Entities/Channels/RpcGroupChannel.cs
  59. +7
    -0
      experiment/Discord.Net.Rpc/Entities/Channels/RpcGuildChannel.cs
  60. +15
    -1
      experiment/Discord.Net.Rpc/Entities/Channels/RpcTextChannel.cs
  61. +0
    -0
      experiment/Discord.Net.Rpc/Entities/Channels/RpcVoiceChannel.cs
  62. +0
    -0
      experiment/Discord.Net.Rpc/Entities/Guilds/RpcGuild.cs
  63. +0
    -0
      experiment/Discord.Net.Rpc/Entities/Guilds/RpcGuildStatus.cs
  64. +0
    -0
      experiment/Discord.Net.Rpc/Entities/Guilds/RpcGuildSummary.cs
  65. +0
    -0
      experiment/Discord.Net.Rpc/Entities/Messages/RpcMessage.cs
  66. +0
    -0
      experiment/Discord.Net.Rpc/Entities/Messages/RpcSystemMessage.cs
  67. +0
    -0
      experiment/Discord.Net.Rpc/Entities/Messages/RpcUserMessage.cs
  68. +0
    -0
      experiment/Discord.Net.Rpc/Entities/RpcEntity.cs
  69. +0
    -0
      experiment/Discord.Net.Rpc/Entities/UserVoiceProperties.cs
  70. +0
    -0
      experiment/Discord.Net.Rpc/Entities/Users/Pan.cs
  71. +0
    -0
      experiment/Discord.Net.Rpc/Entities/Users/RpcGuildUser.cs
  72. +1
    -1
      experiment/Discord.Net.Rpc/Entities/Users/RpcUser.cs
  73. +0
    -0
      experiment/Discord.Net.Rpc/Entities/Users/RpcVoiceState.cs
  74. +0
    -0
      experiment/Discord.Net.Rpc/Entities/Users/RpcWebhookUser.cs
  75. +0
    -0
      experiment/Discord.Net.Rpc/Entities/VoiceDevice.cs
  76. +0
    -0
      experiment/Discord.Net.Rpc/Entities/VoiceDeviceProperties.cs
  77. +0
    -0
      experiment/Discord.Net.Rpc/Entities/VoiceModeProperties.cs
  78. +0
    -0
      experiment/Discord.Net.Rpc/Entities/VoiceProperties.cs
  79. +0
    -0
      experiment/Discord.Net.Rpc/Entities/VoiceSettings.cs
  80. +0
    -0
      experiment/Discord.Net.Rpc/Entities/VoiceShortcut.cs
  81. +0
    -0
      experiment/Discord.Net.Rpc/Entities/VoiceShortcutType.cs
  82. +0
    -0
      experiment/Discord.Net.Rpc/Extensions/EntityExtensions.cs
  83. +0
    -0
      experiment/Discord.Net.Rpc/RpcChannelEvent.cs
  84. +0
    -0
      experiment/Discord.Net.Rpc/RpcGlobalEvent.cs
  85. +0
    -0
      experiment/Discord.Net.Rpc/RpcGuildEvent.cs
  86. +15
    -0
      src/Discord.Net.Analyzers/Discord.Net.Analyzers.csproj
  87. +70
    -0
      src/Discord.Net.Analyzers/GuildAccessAnalyzer.cs
  88. +21
    -0
      src/Discord.Net.Analyzers/SymbolExtensions.cs
  89. +30
    -0
      src/Discord.Net.Analyzers/docs/DNET0001.md
  90. +1
    -1
      src/Discord.Net.Commands/Attributes/AliasAttribute.cs
  91. +2
    -2
      src/Discord.Net.Commands/Attributes/CommandAttribute.cs
  92. +2
    -2
      src/Discord.Net.Commands/Attributes/DontAutoLoadAttribute.cs
  93. +1
    -1
      src/Discord.Net.Commands/Attributes/DontInjectAttribute.cs
  94. +2
    -2
      src/Discord.Net.Commands/Attributes/GroupAttribute.cs
  95. +1
    -1
      src/Discord.Net.Commands/Attributes/NameAttribute.cs
  96. +2
    -2
      src/Discord.Net.Commands/Attributes/OverrideTypeReaderAttribute.cs
  97. +1
    -2
      src/Discord.Net.Commands/Attributes/ParameterPreconditionAttribute.cs
  98. +2
    -2
      src/Discord.Net.Commands/Attributes/Preconditions/RequireContextAttribute.cs
  99. +2
    -2
      src/Discord.Net.Commands/Attributes/Preconditions/RequireNsfwAttribute.cs
  100. +2
    -3
      src/Discord.Net.Commands/Attributes/Preconditions/RequireOwnerAttribute.cs

+ 113
- 0
.editorconfig View File

@@ -0,0 +1,113 @@
# EditorConfig is awesome: http://EditorConfig.org

root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_size = 4
indent_style = space
trim_trailing_whitespace = true

[*.{csproj,json,md,nuspec,yml}]
indent_size = 2
indent_style = space

[*.{sln,xml}]
indent_style = tab

[*.cs]
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:suggestion

dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion

dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion

csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
csharp_style_var_elsewhere = true:suggestion

csharp_style_expression_bodied_methods = true:none
csharp_style_expression_bodied_operators = true:none
csharp_style_expression_bodied_properties = true:none
csharp_style_expression_bodied_indexers = true:none
csharp_style_expression_bodied_accessors = true:none

csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion

csharp_prefer_simple_default_expression = false:none

csharp_style_throw_expression = true:none
csharp_style_conditional_delegate_call = true:none
csharp_prefer_braces = false:none

dotnet_sort_system_directives_first = false

csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_within_query_expression_clauses = true

csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left

csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_method_call_parameter_list_parentheses = false

csharp_preserve_single_line_statements = false
csharp_preserve_single_line_blocks = true

dotnet_naming_rule.all_of_const_fields_are_pascal_case.symbols = const_fields
dotnet_naming_rule.all_of_const_fields_are_pascal_case.style = pascal_case
dotnet_naming_rule.all_of_const_fields_are_pascal_case.severity = suggestion

dotnet_naming_rule.all_of_local_fields_without_const_are_camel_case.symbols = local_fields
dotnet_naming_rule.all_of_local_fields_without_const_are_camel_case.style = starts_with_low_line_camel_case
dotnet_naming_rule.all_of_local_fields_without_const_are_camel_case.severity = suggestion

dotnet_naming_rule.all_of_interfaces_starts_with_low_line_camel_case.symbols = interfaces
dotnet_naming_rule.all_of_interfaces_starts_with_low_line_camel_case.style = starts_with_i_pascal_case
dotnet_naming_rule.all_of_interfaces_starts_with_low_line_camel_case.severity = suggestion

dotnet_naming_rule.default_is_pascal_case.symbols = without_interfaces_and_fields
dotnet_naming_rule.default_is_pascal_case.style = pascal_case
dotnet_naming_rule.default_is_pascal_case.severity = suggestion

dotnet_naming_symbols.const_fields.applicable_kinds = field
dotnet_naming_symbols.const_fields.applicable_accessibilities = *
dotnet_naming_symbols.const_fields.required_modifiers = const

dotnet_naming_symbols.interfaces.applicable_kinds = interface
dotnet_naming_symbols.interfaces.applicable_accessibilities = *

dotnet_naming_symbols.local_fields.applicable_kinds = field
dotnet_naming_symbols.local_fields.applicable_accessibilities = internal, private, protected, protected_internal
dotnet_naming_symbols.local_fields.required_modifiers = abstract, must_inherit, readonly, static, shared

dotnet_naming_symbols.without_interfaces_and_fields.applicable_kinds = class, struct, enum, property, method, event, namespace, delegate, type_parameter
dotnet_naming_symbols.without_interfaces_and_fields.applicable_accessibilities = *

dotnet_naming_style.pascal_case.capitalization = pascal_case

dotnet_naming_style.starts_with_i_pascal_case.required_prefix = I
dotnet_naming_style.starts_with_i_pascal_case.capitalization = pascal_case

dotnet_naming_style.starts_with_low_line_camel_case.required_prefix = _
dotnet_naming_style.starts_with_low_line_camel_case.capitalization = camel_case

+ 44
- 0
CONTRIBUTING.md View File

@@ -0,0 +1,44 @@
# Contributing

Discord.Net is an open-source project, and we appreciate any and all
contributions made by our community. However, please conform to the
following guidelines when possible:

## Development Cycle

We prefer all changes to the library to be discussed beforehand,
either in a GitHub issue, or in a discussion in our Discord channel
with library regulars or other contributors.

Issues that are tagged as "up for grabs" are free to be picked up by
any member of the community.

### Pull Requests

We prefer pull-requests that are descriptive of the changes being made
and highlight any potential benefits/drawbacks of the change, but these
types of write-ups are not required. See this [merge request](https://github.com/RogueException/Discord.Net/pull/793)
for an example of a well-written description.

## Semantic Versioning

This project follows [Semantic Versioning](http://semver.org/). When
writing changes to this project, it is recommended to write changes
that are SemVer compliant with the latest version of the library in
development.

The working release should be the latest build off of the `dev` branch,
but can also be found on the [development board](https://github.com/RogueException/Discord.Net/projects/1).

We follow the .NET Foundation's [Breaking Change Rules](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/breaking-change-rules.md)
when determining the SemVer compliance of a change.

Obsoleting a method is considered a **minor** increment.

## Coding Style

We attempt to conform to the .NET Foundation's [Coding Style](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/coding-style.md)
where possible.

As a general rule, follow the coding style already set in the file you
are editing, or look at a similar file if you are adding a new one.

+ 16
- 16
Discord.Net.sln View File

@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.12
VisualStudioVersion = 15.0.27130.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Core", "src\Discord.Net.Core\Discord.Net.Core.csproj", "{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}"
EndProject
@@ -8,8 +8,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Impls", "Impls", "{288C363D
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Rest", "src\Discord.Net.Rest\Discord.Net.Rest.csproj", "{BFC6DC28-0351-4573-926A-D4124244C04F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Rpc", "src\Discord.Net.Rpc\Discord.Net.Rpc.csproj", "{5688A353-121E-40A1-8BFA-B17B91FB48FB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Commands", "src\Discord.Net.Commands\Discord.Net.Commands.csproj", "{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.WebSocket", "src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj", "{688FD1D8-7F01-4539-B2E9-F473C5D699C7}"
@@ -24,6 +22,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Tests", "test\D
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Webhook", "src\Discord.Net.Webhook\Discord.Net.Webhook.csproj", "{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Analyzers", "src\Discord.Net.Analyzers\Discord.Net.Analyzers.csproj", "{BBA8E7FB-C834-40DC-822F-B112CB7F0140}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -58,18 +58,6 @@ Global
{BFC6DC28-0351-4573-926A-D4124244C04F}.Release|x64.Build.0 = Debug|Any CPU
{BFC6DC28-0351-4573-926A-D4124244C04F}.Release|x86.ActiveCfg = Debug|Any CPU
{BFC6DC28-0351-4573-926A-D4124244C04F}.Release|x86.Build.0 = Debug|Any CPU
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Debug|x64.ActiveCfg = Debug|Any CPU
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Debug|x64.Build.0 = Debug|Any CPU
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Debug|x86.ActiveCfg = Debug|Any CPU
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Debug|x86.Build.0 = Debug|Any CPU
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Release|Any CPU.Build.0 = Release|Any CPU
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Release|x64.ActiveCfg = Debug|Any CPU
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Release|x64.Build.0 = Debug|Any CPU
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Release|x86.ActiveCfg = Debug|Any CPU
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Release|x86.Build.0 = Debug|Any CPU
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -130,17 +118,29 @@ Global
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Release|x64.Build.0 = Release|Any CPU
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Release|x86.ActiveCfg = Release|Any CPU
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Release|x86.Build.0 = Release|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Debug|x64.ActiveCfg = Debug|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Debug|x64.Build.0 = Debug|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Debug|x86.ActiveCfg = Debug|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Debug|x86.Build.0 = Debug|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Release|Any CPU.Build.0 = Release|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Release|x64.ActiveCfg = Release|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Release|x64.Build.0 = Release|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Release|x86.ActiveCfg = Release|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{BFC6DC28-0351-4573-926A-D4124244C04F} = {288C363D-A636-4EAE-9AC1-4698B641B26E}
{5688A353-121E-40A1-8BFA-B17B91FB48FB} = {288C363D-A636-4EAE-9AC1-4698B641B26E}
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}
{688FD1D8-7F01-4539-B2E9-F473C5D699C7} = {288C363D-A636-4EAE-9AC1-4698B641B26E}
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7} = {B0657AAE-DCC5-4FBF-8E5D-1FB578CF3012}
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}
{BBA8E7FB-C834-40DC-822F-B112CB7F0140} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D2404771-EEC8-45F2-9D71-F3373F6C1495}


+ 2
- 2
Discord.Net.targets View File

@@ -1,7 +1,7 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VersionPrefix>2.0.0-alpha</VersionPrefix>
<VersionSuffix></VersionSuffix>
<VersionPrefix>2.0.0</VersionPrefix>
<VersionSuffix>beta</VersionSuffix>
<Authors>RogueException</Authors>
<PackageTags>discord;discordapp</PackageTags>
<PackageProjectUrl>https://github.com/RogueException/Discord.Net</PackageProjectUrl>


+ 2
- 2
README.md View File

@@ -2,11 +2,11 @@
[![NuGet](https://img.shields.io/nuget/vpre/Discord.Net.svg?maxAge=2592000?style=plastic)](https://www.nuget.org/packages/Discord.Net)
[![MyGet](https://img.shields.io/myget/discord-net/vpre/Discord.Net.svg)](https://www.myget.org/feed/Packages/discord-net)
[![Build status](https://ci.appveyor.com/api/projects/status/5sb7n8a09w9clute/branch/dev?svg=true)](https://ci.appveyor.com/project/RogueException/discord-net/branch/dev)
[![Discord](https://discordapp.com/api/guilds/81384788765712384/widget.png)](https://discord.gg/0SBTUU1wZTVjAMPx)
[![Discord](https://discordapp.com/api/guilds/81384788765712384/widget.png)](https://discord.gg/jkrBmQR)

An unofficial .NET API Wrapper for the Discord client (http://discordapp.com).

Check out the [documentation](https://discord.foxbot.me/docs/) or join the [Discord API Chat](https://discord.gg/0SBTUU1wZTVjAMPx).
Check out the [documentation](https://discord.foxbot.me/docs/) or join the [Discord API Chat](https://discord.gg/jkrBmQR).

## Installation
### Stable (NuGet)


+ 2
- 2
appveyor.yml View File

@@ -26,15 +26,15 @@ after_build:
- ps: dotnet pack "src\Discord.Net.Core\Discord.Net.Core.csproj" -c "Release" -o "../../artifacts" --no-build /p:BuildNumber="$Env:BUILD" /p:IsTagBuild="$Env:APPVEYOR_REPO_TAG"
- ps: dotnet pack "src\Discord.Net.Rest\Discord.Net.Rest.csproj" -c "Release" -o "../../artifacts" --no-build /p:BuildNumber="$Env:BUILD" /p:IsTagBuild="$Env:APPVEYOR_REPO_TAG"
- ps: dotnet pack "src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj" -c "Release" -o "../../artifacts" --no-build /p:BuildNumber="$Env:BUILD" /p:IsTagBuild="$Env:APPVEYOR_REPO_TAG"
- ps: dotnet pack "src\Discord.Net.Rpc\Discord.Net.Rpc.csproj" -c "Release" -o "../../artifacts" --no-build /p:BuildNumber="$Env:BUILD" /p:IsTagBuild="$Env:APPVEYOR_REPO_TAG"
- ps: dotnet pack "src\Discord.Net.Commands\Discord.Net.Commands.csproj" -c "Release" -o "../../artifacts" --no-build /p:BuildNumber="$Env:BUILD" /p:IsTagBuild="$Env:APPVEYOR_REPO_TAG"
- ps: dotnet pack "src\Discord.Net.Webhook\Discord.Net.Webhook.csproj" -c "Release" -o "../../artifacts" --no-build /p:BuildNumber="$Env:BUILD" /p:IsTagBuild="$Env:APPVEYOR_REPO_TAG"
- ps: dotnet pack "src\Discord.Net.Providers.WS4Net\Discord.Net.Providers.WS4Net.csproj" -c "Release" -o "../../artifacts" --no-build /p:BuildNumber="$Env:BUILD" /p:IsTagBuild="$Env:APPVEYOR_REPO_TAG"
- ps: dotnet pack "src\Discord.Net.Analyzers\Discord.Net.Analyzers.csproj" -c "Release" -o "../../artifacts" --no-build /p:BuildNumber="$Env:BUILD" /p:IsTagBuild="$Env:APPVEYOR_REPO_TAG"
- ps: >-
if ($Env:APPVEYOR_REPO_TAG -eq "true") {
nuget pack src\Discord.Net\Discord.Net.nuspec -OutputDirectory "artifacts" -properties suffix=""
} else {
nuget pack src\Discord.Net\Discord.Net.nuspec -OutputDirectory "artifacts" -properties suffix="-build-$Env:BUILD"
nuget pack src\Discord.Net\Discord.Net.nuspec -OutputDirectory "artifacts" -properties suffix="-$Env:BUILD"
}
- ps: Get-ChildItem artifacts\*.nupkg | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }



+ 3
- 3
docs/guides/commands/commands.md View File

@@ -93,9 +93,9 @@ If you would like a parameter to parse until the end of a Command,
flag the parameter with the [RemainderAttribute]. This will allow a
user to invoke a Command without wrapping a parameter in quotes.

Finally, flag your Command with the [CommandAttribute] (you must
Finally, flag your Command with the [CommandAttribute]. (you must
specify a name for this Command, except for when it is part of a
Module Group - see below).
Module Group - see below)

[RemainderAttribute]: xref:Discord.Commands.RemainderAttribute
[CommandAttribute]: xref:Discord.Commands.CommandAttribute
@@ -340,4 +340,4 @@ and must be explicitly added.

To install a TypeReader, invoke [CommandService.AddTypeReader].

[CommandService.AddTypeReader]: xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddTypeReader__1_Discord_Commands_TypeReader_
[CommandService.AddTypeReader]: xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddTypeReader__1_Discord_Commands_TypeReader_

src/Discord.Net.Rpc/API/Rpc/AuthenticateParams.cs → experiment/Discord.Net.Rpc/API/Rpc/AuthenticateParams.cs View File


src/Discord.Net.Rpc/API/Rpc/AuthenticateResponse.cs → experiment/Discord.Net.Rpc/API/Rpc/AuthenticateResponse.cs View File


src/Discord.Net.Rpc/API/Rpc/AuthorizeParams.cs → experiment/Discord.Net.Rpc/API/Rpc/AuthorizeParams.cs View File


src/Discord.Net.Rpc/API/Rpc/AuthorizeResponse.cs → experiment/Discord.Net.Rpc/API/Rpc/AuthorizeResponse.cs View File


src/Discord.Net.Rpc/API/Rpc/Channel.cs → experiment/Discord.Net.Rpc/API/Rpc/Channel.cs View File


src/Discord.Net.Rpc/API/Rpc/ChannelSubscriptionParams.cs → experiment/Discord.Net.Rpc/API/Rpc/ChannelSubscriptionParams.cs View File


src/Discord.Net.Rpc/API/Rpc/ChannelSummary.cs → experiment/Discord.Net.Rpc/API/Rpc/ChannelSummary.cs View File


src/Discord.Net.Rpc/API/Rpc/ErrorEvent.cs → experiment/Discord.Net.Rpc/API/Rpc/ErrorEvent.cs View File


src/Discord.Net.Rpc/API/Rpc/ExtendedVoiceState.cs → experiment/Discord.Net.Rpc/API/Rpc/ExtendedVoiceState.cs View File


src/Discord.Net.Rpc/API/Rpc/GetChannelParams.cs → experiment/Discord.Net.Rpc/API/Rpc/GetChannelParams.cs View File


src/Discord.Net.Rpc/API/Rpc/GetChannelsParams.cs → experiment/Discord.Net.Rpc/API/Rpc/GetChannelsParams.cs View File


src/Discord.Net.Rpc/API/Rpc/GetChannelsResponse.cs → experiment/Discord.Net.Rpc/API/Rpc/GetChannelsResponse.cs View File


src/Discord.Net.Rpc/API/Rpc/GetGuildParams.cs → experiment/Discord.Net.Rpc/API/Rpc/GetGuildParams.cs View File


src/Discord.Net.Rpc/API/Rpc/GetGuildsParams.cs → experiment/Discord.Net.Rpc/API/Rpc/GetGuildsParams.cs View File


src/Discord.Net.Rpc/API/Rpc/GetGuildsResponse.cs → experiment/Discord.Net.Rpc/API/Rpc/GetGuildsResponse.cs View File


src/Discord.Net.Rpc/API/Rpc/Guild.cs → experiment/Discord.Net.Rpc/API/Rpc/Guild.cs View File


src/Discord.Net.Rpc/API/Rpc/GuildMember.cs → experiment/Discord.Net.Rpc/API/Rpc/GuildMember.cs View File


src/Discord.Net.Rpc/API/Rpc/GuildStatusEvent.cs → experiment/Discord.Net.Rpc/API/Rpc/GuildStatusEvent.cs View File


src/Discord.Net.Rpc/API/Rpc/GuildSubscriptionParams.cs → experiment/Discord.Net.Rpc/API/Rpc/GuildSubscriptionParams.cs View File


src/Discord.Net.Rpc/API/Rpc/GuildSummary.cs → experiment/Discord.Net.Rpc/API/Rpc/GuildSummary.cs View File


src/Discord.Net.Rpc/API/Rpc/Message.cs → experiment/Discord.Net.Rpc/API/Rpc/Message.cs View File


src/Discord.Net.Rpc/API/Rpc/MessageEvent.cs → experiment/Discord.Net.Rpc/API/Rpc/MessageEvent.cs View File


src/Discord.Net.Rpc/API/Rpc/Pan.cs → experiment/Discord.Net.Rpc/API/Rpc/Pan.cs View File


src/Discord.Net.Rpc/API/Rpc/ReadyEvent.cs → experiment/Discord.Net.Rpc/API/Rpc/ReadyEvent.cs View File


src/Discord.Net.Rpc/API/Rpc/RpcConfig.cs → experiment/Discord.Net.Rpc/API/Rpc/RpcConfig.cs View File


src/Discord.Net.Rpc/API/Rpc/SelectChannelParams.cs → experiment/Discord.Net.Rpc/API/Rpc/SelectChannelParams.cs View File


src/Discord.Net.Rpc/API/Rpc/SetLocalVolumeParams.cs → experiment/Discord.Net.Rpc/API/Rpc/SetLocalVolumeParams.cs View File


src/Discord.Net.Rpc/API/Rpc/SetLocalVolumeResponse.cs → experiment/Discord.Net.Rpc/API/Rpc/SetLocalVolumeResponse.cs View File


src/Discord.Net.Rpc/API/Rpc/SpeakingEvent.cs → experiment/Discord.Net.Rpc/API/Rpc/SpeakingEvent.cs View File


src/Discord.Net.Rpc/API/Rpc/SubscriptionResponse.cs → experiment/Discord.Net.Rpc/API/Rpc/SubscriptionResponse.cs View File


src/Discord.Net.Rpc/API/Rpc/UserVoiceSettings.cs → experiment/Discord.Net.Rpc/API/Rpc/UserVoiceSettings.cs View File


src/Discord.Net.Rpc/API/Rpc/VoiceDevice.cs → experiment/Discord.Net.Rpc/API/Rpc/VoiceDevice.cs View File


src/Discord.Net.Rpc/API/Rpc/VoiceDeviceSettings.cs → experiment/Discord.Net.Rpc/API/Rpc/VoiceDeviceSettings.cs View File


src/Discord.Net.Rpc/API/Rpc/VoiceMode.cs → experiment/Discord.Net.Rpc/API/Rpc/VoiceMode.cs View File


src/Discord.Net.Rpc/API/Rpc/VoiceSettings.cs → experiment/Discord.Net.Rpc/API/Rpc/VoiceSettings.cs View File


src/Discord.Net.Rpc/API/Rpc/VoiceShortcut.cs → experiment/Discord.Net.Rpc/API/Rpc/VoiceShortcut.cs View File


src/Discord.Net.Rpc/API/RpcFrame.cs → experiment/Discord.Net.Rpc/API/RpcFrame.cs View File


src/Discord.Net.Rpc/AssemblyInfo.cs → experiment/Discord.Net.Rpc/AssemblyInfo.cs View File


src/Discord.Net.Rpc/Commands/RpcCommandContext.cs → experiment/Discord.Net.Rpc/Commands/RpcCommandContext.cs View File


src/Discord.Net.Rpc/Discord.Net.Rpc.csproj → experiment/Discord.Net.Rpc/Discord.Net.Rpc.csproj View File


src/Discord.Net.Rpc/DiscordRpcApiClient.cs → experiment/Discord.Net.Rpc/DiscordRpcApiClient.cs View File


src/Discord.Net.Rpc/DiscordRpcClient.Events.cs → experiment/Discord.Net.Rpc/DiscordRpcClient.Events.cs View File


src/Discord.Net.Rpc/DiscordRpcClient.cs → experiment/Discord.Net.Rpc/DiscordRpcClient.cs View File


src/Discord.Net.Rpc/DiscordRpcConfig.cs → experiment/Discord.Net.Rpc/DiscordRpcConfig.cs View File


src/Discord.Net.Rpc/Entities/Channels/IRpcAudioChannel.cs → experiment/Discord.Net.Rpc/Entities/Channels/IRpcAudioChannel.cs View File


src/Discord.Net.Rpc/Entities/Channels/IRpcMessageChannel.cs → experiment/Discord.Net.Rpc/Entities/Channels/IRpcMessageChannel.cs View File


src/Discord.Net.Rpc/Entities/Channels/IRpcPrivateChannel.cs → experiment/Discord.Net.Rpc/Entities/Channels/IRpcPrivateChannel.cs View File


src/Discord.Net.Rpc/Entities/Channels/RpcChannel.cs → experiment/Discord.Net.Rpc/Entities/Channels/RpcChannel.cs View File


src/Discord.Net.Rpc/Entities/Channels/RpcChannelSummary.cs → experiment/Discord.Net.Rpc/Entities/Channels/RpcChannelSummary.cs View File


src/Discord.Net.Rpc/Entities/Channels/RpcDMChannel.cs → experiment/Discord.Net.Rpc/Entities/Channels/RpcDMChannel.cs View File


src/Discord.Net.Rpc/Entities/Channels/RpcGroupChannel.cs → experiment/Discord.Net.Rpc/Entities/Channels/RpcGroupChannel.cs View File


src/Discord.Net.Rpc/Entities/Channels/RpcGuildChannel.cs → experiment/Discord.Net.Rpc/Entities/Channels/RpcGuildChannel.cs View File

@@ -10,6 +10,7 @@ namespace Discord.Rpc
{
public ulong GuildId { get; }
public int Position { get; private set; }
public ulong? CategoryId { get; private set; }

internal RpcGuildChannel(DiscordRpcClient discord, ulong id, ulong guildId)
: base(discord, id)
@@ -57,6 +58,12 @@ namespace Discord.Rpc
public override string ToString() => Name;

//IGuildChannel
public Task<ICategoryChannel> GetCategoryAsync()
{
//Always fails
throw new InvalidOperationException("Unable to return this entity's parent unless it was fetched through that object.");
}

IGuild IGuildChannel.Guild
{
get

src/Discord.Net.Rpc/Entities/Channels/RpcTextChannel.cs → experiment/Discord.Net.Rpc/Entities/Channels/RpcTextChannel.cs View File

@@ -68,11 +68,25 @@ namespace Discord.Rpc
=> ChannelHelper.TriggerTypingAsync(this, Discord, options);
public IDisposable EnterTypingState(RequestOptions options = null)
=> ChannelHelper.EnterTypingState(this, Discord, options);

//Webhooks
public Task<RestWebhook> CreateWebhookAsync(string name, Stream avatar = null, RequestOptions options = null)
=> ChannelHelper.CreateWebhookAsync(this, Discord, name, avatar, options);
public Task<RestWebhook> GetWebhookAsync(ulong id, RequestOptions options = null)
=> ChannelHelper.GetWebhookAsync(this, Discord, id, options);
public Task<IReadOnlyCollection<RestWebhook>> GetWebhooksAsync(RequestOptions options = null)
=> ChannelHelper.GetWebhooksAsync(this, Discord, options);

private string DebuggerDisplay => $"{Name} ({Id}, Text)";
//ITextChannel
string ITextChannel.Topic { get { throw new NotSupportedException(); } }
async Task<IWebhook> ITextChannel.CreateWebhookAsync(string name, Stream avatar, RequestOptions options)
=> await CreateWebhookAsync(name, avatar, options);
async Task<IWebhook> ITextChannel.GetWebhookAsync(ulong id, RequestOptions options)
=> await GetWebhookAsync(id, options);
async Task<IReadOnlyCollection<IWebhook>> ITextChannel.GetWebhooksAsync(RequestOptions options)
=> await GetWebhooksAsync(options);

//IMessageChannel
async Task<IMessage> IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options)

src/Discord.Net.Rpc/Entities/Channels/RpcVoiceChannel.cs → experiment/Discord.Net.Rpc/Entities/Channels/RpcVoiceChannel.cs View File


src/Discord.Net.Rpc/Entities/Guilds/RpcGuild.cs → experiment/Discord.Net.Rpc/Entities/Guilds/RpcGuild.cs View File


src/Discord.Net.Rpc/Entities/Guilds/RpcGuildStatus.cs → experiment/Discord.Net.Rpc/Entities/Guilds/RpcGuildStatus.cs View File


src/Discord.Net.Rpc/Entities/Guilds/RpcGuildSummary.cs → experiment/Discord.Net.Rpc/Entities/Guilds/RpcGuildSummary.cs View File


src/Discord.Net.Rpc/Entities/Messages/RpcMessage.cs → experiment/Discord.Net.Rpc/Entities/Messages/RpcMessage.cs View File


src/Discord.Net.Rpc/Entities/Messages/RpcSystemMessage.cs → experiment/Discord.Net.Rpc/Entities/Messages/RpcSystemMessage.cs View File


src/Discord.Net.Rpc/Entities/Messages/RpcUserMessage.cs → experiment/Discord.Net.Rpc/Entities/Messages/RpcUserMessage.cs View File


src/Discord.Net.Rpc/Entities/RpcEntity.cs → experiment/Discord.Net.Rpc/Entities/RpcEntity.cs View File


src/Discord.Net.Rpc/Entities/UserVoiceProperties.cs → experiment/Discord.Net.Rpc/Entities/UserVoiceProperties.cs View File


src/Discord.Net.Rpc/Entities/Users/Pan.cs → experiment/Discord.Net.Rpc/Entities/Users/Pan.cs View File


src/Discord.Net.Rpc/Entities/Users/RpcGuildUser.cs → experiment/Discord.Net.Rpc/Entities/Users/RpcGuildUser.cs View File


src/Discord.Net.Rpc/Entities/Users/RpcUser.cs → experiment/Discord.Net.Rpc/Entities/Users/RpcUser.cs View File

@@ -18,7 +18,7 @@ namespace Discord.Rpc
public string Discriminator => DiscriminatorValue.ToString("D4");
public string Mention => MentionUtils.MentionUser(Id);
public virtual bool IsWebhook => false;
public virtual Game? Game => null;
public virtual IActivity Activity => null;
public virtual UserStatus Status => UserStatus.Offline;

internal RpcUser(DiscordRpcClient discord, ulong id)

src/Discord.Net.Rpc/Entities/Users/RpcVoiceState.cs → experiment/Discord.Net.Rpc/Entities/Users/RpcVoiceState.cs View File


src/Discord.Net.Rpc/Entities/Users/RpcWebhookUser.cs → experiment/Discord.Net.Rpc/Entities/Users/RpcWebhookUser.cs View File


src/Discord.Net.Rpc/Entities/VoiceDevice.cs → experiment/Discord.Net.Rpc/Entities/VoiceDevice.cs View File


src/Discord.Net.Rpc/Entities/VoiceDeviceProperties.cs → experiment/Discord.Net.Rpc/Entities/VoiceDeviceProperties.cs View File


src/Discord.Net.Rpc/Entities/VoiceModeProperties.cs → experiment/Discord.Net.Rpc/Entities/VoiceModeProperties.cs View File


src/Discord.Net.Rpc/Entities/VoiceProperties.cs → experiment/Discord.Net.Rpc/Entities/VoiceProperties.cs View File


src/Discord.Net.Rpc/Entities/VoiceSettings.cs → experiment/Discord.Net.Rpc/Entities/VoiceSettings.cs View File


src/Discord.Net.Rpc/Entities/VoiceShortcut.cs → experiment/Discord.Net.Rpc/Entities/VoiceShortcut.cs View File


src/Discord.Net.Rpc/Entities/VoiceShortcutType.cs → experiment/Discord.Net.Rpc/Entities/VoiceShortcutType.cs View File


src/Discord.Net.Rpc/Extensions/EntityExtensions.cs → experiment/Discord.Net.Rpc/Extensions/EntityExtensions.cs View File


src/Discord.Net.Rpc/RpcChannelEvent.cs → experiment/Discord.Net.Rpc/RpcChannelEvent.cs View File


src/Discord.Net.Rpc/RpcGlobalEvent.cs → experiment/Discord.Net.Rpc/RpcGlobalEvent.cs View File


src/Discord.Net.Rpc/RpcGuildEvent.cs → experiment/Discord.Net.Rpc/RpcGuildEvent.cs View File


+ 15
- 0
src/Discord.Net.Analyzers/Discord.Net.Analyzers.csproj View File

@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="../../Discord.Net.targets" />
<PropertyGroup>
<AssemblyName>Discord.Net.Analyzers</AssemblyName>
<RootNamespace>Discord.Analyzers</RootNamespace>
<Description>A Discord.Net extension adding support for design-time analysis of the API usage.</Description>
<TargetFramework>netstandard1.3</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis" Version="2.6.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Discord.Net.Commands\Discord.Net.Commands.csproj" />
</ItemGroup>
</Project>

+ 70
- 0
src/Discord.Net.Analyzers/GuildAccessAnalyzer.cs View File

@@ -0,0 +1,70 @@
using System;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Discord.Commands;

namespace Discord.Analyzers
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class GuildAccessAnalyzer : DiagnosticAnalyzer
{
private const string DiagnosticId = "DNET0001";
private const string Title = "Limit command to Guild contexts.";
private const string MessageFormat = "Command method '{0}' is accessing 'Context.Guild' but is not restricted to Guild contexts.";
private const string Description = "Accessing 'Context.Guild' in a command without limiting the command to run only in guilds.";
private const string Category = "API Usage";

private static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);

public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeMemberAccess, SyntaxKind.SimpleMemberAccessExpression);
}

private static void AnalyzeMemberAccess(SyntaxNodeAnalysisContext context)
{
// Bail out if the accessed member isn't named 'Guild'
var memberAccessSymbol = context.SemanticModel.GetSymbolInfo(context.Node).Symbol;
if (memberAccessSymbol.Name != "Guild")
return;

// Bail out if it happens to be 'ContextType.Guild' in the '[RequireContext]' argument
if (context.Node.Parent is AttributeArgumentSyntax)
return;

// Bail out if the containing class doesn't derive from 'ModuleBase<T>'
var typeNode = context.Node.FirstAncestorOrSelf<TypeDeclarationSyntax>();
var typeSymbol = context.SemanticModel.GetDeclaredSymbol(typeNode);
if (!typeSymbol.DerivesFromModuleBase())
return;

// Bail out if the containing method isn't marked with '[Command]'
var methodNode = context.Node.FirstAncestorOrSelf<MethodDeclarationSyntax>();
var methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodNode);
var methodAttributes = methodSymbol.GetAttributes();
if (!methodAttributes.Any(a => a.AttributeClass.Name == nameof(CommandAttribute)))
return;

// Is the '[RequireContext]' attribute not applied to either the
// method or the class, or its argument isn't 'ContextType.Guild'?
var ctxAttribute = methodAttributes.SingleOrDefault(_attributeDataPredicate)
?? typeSymbol.GetAttributes().SingleOrDefault(_attributeDataPredicate);

if (ctxAttribute == null || ctxAttribute.ConstructorArguments.Any(arg => !arg.Value.Equals((int)ContextType.Guild)))
{
// Report the diagnostic
var diagnostic = Diagnostic.Create(Rule, context.Node.GetLocation(), methodSymbol.Name);
context.ReportDiagnostic(diagnostic);
}
}

private static readonly Func<AttributeData, bool> _attributeDataPredicate =
(a => a.AttributeClass.Name == nameof(RequireContextAttribute));
}
}

+ 21
- 0
src/Discord.Net.Analyzers/SymbolExtensions.cs View File

@@ -0,0 +1,21 @@
using System;
using Microsoft.CodeAnalysis;
using Discord.Commands;

namespace Discord.Analyzers
{
internal static class SymbolExtensions
{
private static readonly string _moduleBaseName = typeof(ModuleBase<>).Name;

public static bool DerivesFromModuleBase(this ITypeSymbol symbol)
{
for (var bType = symbol.BaseType; bType != null; bType = bType.BaseType)
{
if (bType.MetadataName == _moduleBaseName)
return true;
}
return false;
}
}
}

+ 30
- 0
src/Discord.Net.Analyzers/docs/DNET0001.md View File

@@ -0,0 +1,30 @@
# DNET0001

<table>
<tr>
<td>TypeName</td>
<td>GuildAccessAnalyzer</td>
</tr>
<tr>
<td>CheckId</td>
<td>DNET0001</td>
</tr>
<tr>
<td>Category</td>
<td>API Usage</td>
</tr>
</table>

## Cause

A method identified as a command is accessing `Context.Guild` without the requisite precondition.

## Rule description

The value of `Context.Guild` is `null` if a command is invoked in a DM channel. Attempting to access
guild properties in such a case will result in a `NullReferenceException` at runtime.
This exception is entirely avoidable by using the library's provided preconditions.

## How to fix violations

Add the precondition `[RequireContext(ContextType.Guild)]` to the command or module class.

+ 1
- 1
src/Discord.Net.Commands/Attributes/AliasAttribute.cs View File

@@ -3,7 +3,7 @@ using System;
namespace Discord.Commands
{
/// <summary> Provides aliases for a command. </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class AliasAttribute : Attribute
{
/// <summary> The aliases which have been defined for the command. </summary>


+ 2
- 2
src/Discord.Net.Commands/Attributes/CommandAttribute.cs View File

@@ -1,8 +1,8 @@
using System;
using System;

namespace Discord.Commands
{
[AttributeUsage(AttributeTargets.Method)]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class CommandAttribute : Attribute
{
public string Text { get; }


+ 2
- 2
src/Discord.Net.Commands/Attributes/DontAutoLoadAttribute.cs View File

@@ -1,8 +1,8 @@
using System;
using System;

namespace Discord.Commands
{
[AttributeUsage(AttributeTargets.Class)]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class DontAutoLoadAttribute : Attribute
{
}


+ 1
- 1
src/Discord.Net.Commands/Attributes/DontInjectAttribute.cs View File

@@ -2,7 +2,7 @@ using System;

namespace Discord.Commands {

[AttributeUsage(AttributeTargets.Property)]
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class DontInjectAttribute : Attribute {
}



+ 2
- 2
src/Discord.Net.Commands/Attributes/GroupAttribute.cs View File

@@ -1,8 +1,8 @@
using System;
using System;

namespace Discord.Commands
{
[AttributeUsage(AttributeTargets.Class)]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class GroupAttribute : Attribute
{
public string Prefix { get; }


+ 1
- 1
src/Discord.Net.Commands/Attributes/NameAttribute.cs View File

@@ -3,7 +3,7 @@ using System;
namespace Discord.Commands
{
// Override public name of command/module
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Parameter)]
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
public class NameAttribute : Attribute
{
public string Text { get; }


+ 2
- 2
src/Discord.Net.Commands/Attributes/OverrideTypeReaderAttribute.cs View File

@@ -4,7 +4,7 @@ using System.Reflection;

namespace Discord.Commands
{
[AttributeUsage(AttributeTargets.Parameter)]
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
public class OverrideTypeReaderAttribute : Attribute
{
private static readonly TypeInfo _typeReaderTypeInfo = typeof(TypeReader).GetTypeInfo();
@@ -19,4 +19,4 @@ namespace Discord.Commands
TypeReader = overridenTypeReader;
}
}
}
}

+ 1
- 2
src/Discord.Net.Commands/Attributes/ParameterPreconditionAttribute.cs View File

@@ -1,6 +1,5 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;

namespace Discord.Commands
{
@@ -9,4 +8,4 @@ namespace Discord.Commands
{
public abstract Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, ParameterInfo parameter, object value, IServiceProvider services);
}
}
}

+ 2
- 2
src/Discord.Net.Commands/Attributes/Preconditions/RequireContextAttribute.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;

@@ -15,7 +15,7 @@ namespace Discord.Commands
/// <summary>
/// Require that the command be invoked in a specified context.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class RequireContextAttribute : PreconditionAttribute
{
public ContextType Contexts { get; }


+ 2
- 2
src/Discord.Net.Commands/Attributes/Preconditions/RequireNsfwAttribute.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Threading.Tasks;

namespace Discord.Commands
@@ -6,7 +6,7 @@ namespace Discord.Commands
/// <summary>
/// Require that the command is invoked in a channel marked NSFW
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class RequireNsfwAttribute : PreconditionAttribute
{
public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)


+ 2
- 3
src/Discord.Net.Commands/Attributes/Preconditions/RequireOwnerAttribute.cs View File

@@ -1,7 +1,6 @@
#pragma warning disable CS0618
#pragma warning disable CS0618
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;

namespace Discord.Commands
{
@@ -9,7 +8,7 @@ namespace Discord.Commands
/// Require that the command is invoked by the owner of the bot.
/// </summary>
/// <remarks>This precondition will only work if the bot is a bot account.</remarks>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class RequireOwnerAttribute : PreconditionAttribute
{
public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save