Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Include NonCopyableAnalyzer#1615

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Closed
filmor wants to merge4 commits intopythonnet:masterfromfilmor:include-analyzer
Closed
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletionsDirectory.Build.props
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,9 +13,9 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Lost.NonCopyableAnalyzer" Version="0.7.0-m04">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<ProjectReference Include="$(MSBuildThisFileDirectory)src\noncopyable_analyzer\NonCopyable.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<OutputItemType>Analyzer</OutputItemType>
</ProjectReference>
</ItemGroup>
</Project>
21 changes: 20 additions & 1 deletionpythonnet.sln
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30717.126
MinimumVisualStudioVersion = 15.0.26124.0
Expand DownExpand Up@@ -46,6 +46,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{142A6752
Directory.Build.props = Directory.Build.props
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D4963EF0-46CD-43AF-939D-BA47C1B091D1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NonCopyable", "src\noncopyable_analyzer\NonCopyable.csproj", "{CA041F36-A4C2-4B18-9501-F670FDED87F4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand DownExpand Up@@ -152,11 +156,26 @@ Global
{35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.Release|x64.Build.0 = Release|Any CPU
{35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.Release|x86.ActiveCfg = Release|Any CPU
{35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.Release|x86.Build.0 = Release|Any CPU
{CA041F36-A4C2-4B18-9501-F670FDED87F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CA041F36-A4C2-4B18-9501-F670FDED87F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CA041F36-A4C2-4B18-9501-F670FDED87F4}.Debug|x64.ActiveCfg = Debug|Any CPU
{CA041F36-A4C2-4B18-9501-F670FDED87F4}.Debug|x64.Build.0 = Debug|Any CPU
{CA041F36-A4C2-4B18-9501-F670FDED87F4}.Debug|x86.ActiveCfg = Debug|Any CPU
{CA041F36-A4C2-4B18-9501-F670FDED87F4}.Debug|x86.Build.0 = Debug|Any CPU
{CA041F36-A4C2-4B18-9501-F670FDED87F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CA041F36-A4C2-4B18-9501-F670FDED87F4}.Release|Any CPU.Build.0 = Release|Any CPU
{CA041F36-A4C2-4B18-9501-F670FDED87F4}.Release|x64.ActiveCfg = Release|Any CPU
{CA041F36-A4C2-4B18-9501-F670FDED87F4}.Release|x64.Build.0 = Release|Any CPU
{CA041F36-A4C2-4B18-9501-F670FDED87F4}.Release|x86.ActiveCfg = Release|Any CPU
{CA041F36-A4C2-4B18-9501-F670FDED87F4}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C8845072-C642-4858-8627-27E862AD21BB}
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{CA041F36-A4C2-4B18-9501-F670FDED87F4} = {D4963EF0-46CD-43AF-939D-BA47C1B091D1}
EndGlobalSection
EndGlobal
21 changes: 21 additions & 0 deletionssrc/noncopyable_analyzer/LICENSE
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2017 Nobuyuki Iwanaga

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.
27 changes: 27 additions & 0 deletionssrc/noncopyable_analyzer/NonCopyable.csproj
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<IncludeBuildOutput>false</IncludeBuildOutput>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<LangVersion>latest</LangVersion>
</PropertyGroup>

<PropertyGroup>
<PackageId>PythonNet.NonCopyableAnalyzer</PackageId>
<Authors>Nobuyuki Iwanaga</Authors>
<PackageLicenseUrl>https://github.com/ufcpp/NonCopyableAnalyzer/blob/master/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>https://github.com/ufcpp/NonCopyableAnalyzer</PackageProjectUrl>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<Description>Analyzer for Non-copyable struct</Description>
<PackageReleaseNotes>Fixed false positive on conversion operators with in argument.</PackageReleaseNotes>
<PackageTags>NonCopyable, analyzers</PackageTags>
<NoPackageAnalysis>true</NoPackageAnalysis>
</PropertyGroup>

<ItemGroup>
<ProjectReference Remove="$(MSBuildThisFile)" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="2.6.0" PrivateAssets="all" />
</ItemGroup>

</Project>
256 changes: 256 additions & 0 deletionssrc/noncopyable_analyzer/NonCopyableAnalyzer.cs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;

namespace NonCopyable
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class NonCopyableAnalyzer : DiagnosticAnalyzer
{
private static DiagnosticDescriptor CreateRule(int num, string type)
=> new DiagnosticDescriptor("NoCopy" + num.ToString("00"), "non-copyable", "🚫 " + type + ". '{0}' is non-copyable.", "Correction", DiagnosticSeverity.Error, isEnabledByDefault: true);

private static DiagnosticDescriptor FieldDeclarationRule = CreateRule(1, "field declaration");
private static DiagnosticDescriptor InitializerRule = CreateRule(2, "initializer");
private static DiagnosticDescriptor AssignmentRule = CreateRule(3, "assignment");
private static DiagnosticDescriptor ArgumentRule = CreateRule(4, "argument");
private static DiagnosticDescriptor ReturnRule = CreateRule(5, "return");
private static DiagnosticDescriptor ConversionRule = CreateRule(6, "conversion");
private static DiagnosticDescriptor PatternRule = CreateRule(7, "pattern matching");
private static DiagnosticDescriptor TupleRule = CreateRule(8, "tuple");
private static DiagnosticDescriptor MemberRule = CreateRule(9, "member reference");
private static DiagnosticDescriptor ReadOnlyInvokeRule = CreateRule(10, "readonly invoke");
private static DiagnosticDescriptor GenericConstraintRule = CreateRule(11, "generic constraint");
private static DiagnosticDescriptor DelegateRule = CreateRule(12, "delegate");

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(FieldDeclarationRule, InitializerRule, AssignmentRule, ArgumentRule, ReturnRule, ConversionRule, PatternRule, TupleRule, MemberRule, ReadOnlyInvokeRule, GenericConstraintRule, DelegateRule);

public override void Initialize(AnalysisContext context)
{
context.RegisterCompilationStartAction(csc =>
{
csc.RegisterOperationAction(oc =>
{
var op = (ISymbolInitializerOperation)oc.Operation;
CheckCopyability(oc, op.Value, InitializerRule);
}, OperationKind.FieldInitializer,
OperationKind.ParameterInitializer,
OperationKind.PropertyInitializer,
OperationKind.VariableInitializer);

csc.RegisterOperationAction(oc =>
{
// including member initializer
// including collection element initializer
var op = (ISimpleAssignmentOperation)oc.Operation;
if (op.IsRef) return;
CheckCopyability(oc, op.Value, AssignmentRule);
}, OperationKind.SimpleAssignment);

csc.RegisterOperationAction(oc =>
{
// including non-ref extension method invocation
var op = (IArgumentOperation)oc.Operation;
if (op.Parameter.RefKind != RefKind.None) return;
CheckCopyability(oc, op.Value, ArgumentRule);
}, OperationKind.Argument);

csc.RegisterOperationAction(oc =>
{
var op = (IReturnOperation)oc.Operation;
if (op.ReturnedValue == null) return;
CheckCopyability(oc, op.ReturnedValue, ReturnRule);
}, OperationKind.Return,
OperationKind.YieldReturn);

csc.RegisterOperationAction(oc =>
{
var op = (IConversionOperation)oc.Operation;
var v = op.Operand;
if (v.Kind == OperationKind.DefaultValue) return;
var t = v.Type;
if (!t.IsNonCopyable()) return;

if (op.OperatorMethod != null && op.OperatorMethod.Parameters.Length == 1)
{
var parameter = op.OperatorMethod.Parameters[0];
if (parameter.RefKind != RefKind.None) return;
}

if (op.Parent is IForEachLoopOperation &&
op == ((IForEachLoopOperation)op.Parent).Collection &&
op.Conversion.IsIdentity)
{
return;
}

oc.ReportDiagnostic(Error(v.Syntax, ConversionRule, t.Name));
}, OperationKind.Conversion);

csc.RegisterOperationAction(oc =>
{
var op = (IArrayInitializerOperation)oc.Operation;

if (!((IArrayTypeSymbol)((IArrayCreationOperation)op.Parent).Type).ElementType.IsNonCopyable()) return;

foreach (var v in op.ElementValues)
{
CheckCopyability(oc, v, InitializerRule);
}
}, OperationKind.ArrayInitializer);

csc.RegisterOperationAction(oc =>
{
var op = (IDeclarationPatternOperation)oc.Operation;
var t = ((ILocalSymbol)op.DeclaredSymbol).Type;
if (!t.IsNonCopyable()) return;
oc.ReportDiagnostic(Error(op.Syntax, PatternRule, t.Name));
}, OperationKind.DeclarationPattern);

csc.RegisterOperationAction(oc =>
{
var op = (ITupleOperation)oc.Operation;

// exclude ParenthesizedVariableDesignationSyntax
if (op.Syntax.Kind() != SyntaxKind.TupleExpression) return;

foreach (var v in op.Elements)
{
CheckCopyability(oc, v, TupleRule);
}
}, OperationKind.Tuple);

csc.RegisterOperationAction(oc =>
{
// instance property/event should not be referenced with in parameter/ref readonly local/readonly field
var op = (IMemberReferenceOperation)oc.Operation;
CheckInstanceReadonly(oc, op.Instance, MemberRule);
}, OperationKind.PropertyReference,
OperationKind.EventReference);

csc.RegisterOperationAction(oc =>
{
// instance method should not be invoked with in parameter/ref readonly local/readonly field
var op = (IInvocationOperation)oc.Operation;

CheckGenericConstraints(oc, op, GenericConstraintRule);
CheckInstanceReadonly(oc, op.Instance, ReadOnlyInvokeRule);

}, OperationKind.Invocation);

csc.RegisterOperationAction(oc => {
var op = (IDynamicInvocationOperation)oc.Operation;

foreach(var arg in op.Arguments) {
if (!arg.Type.IsNonCopyable()) continue;

oc.ReportDiagnostic(Error(arg.Syntax, GenericConstraintRule));
}

}, OperationKind.DynamicInvocation);

csc.RegisterOperationAction(oc =>
{
// delagate creation
var op = (IMemberReferenceOperation)oc.Operation;
if (op.Instance == null) return;
if (!op.Instance.Type.IsNonCopyable()) return;
oc.ReportDiagnostic(Error(op.Instance.Syntax, DelegateRule, op.Instance.Type.Name));
}, OperationKind.MethodReference);

csc.RegisterSymbolAction(sac =>
{
var f = (IFieldSymbol)sac.Symbol;
if (f.IsStatic) return;
if (!f.Type.IsNonCopyable()) return;
if (f.ContainingType.IsReferenceType) return;
if (f.ContainingType.IsNonCopyable()) return;
sac.ReportDiagnostic(Error(f.DeclaringSyntaxReferences[0].GetSyntax(), FieldDeclarationRule, f.Type.Name));
}, SymbolKind.Field);
});

// not supported yet:
// OperationKind.CompoundAssignment,
// OperationKind.UnaryOperator,
// OperationKind.BinaryOperator,
}

private static void CheckGenericConstraints(in OperationAnalysisContext oc, IInvocationOperation op, DiagnosticDescriptor rule)
{
var m = op.TargetMethod;

if (m.IsGenericMethod)
{
var parameters = m.TypeParameters;
var arguments = m.TypeArguments;
for (int i = 0; i < parameters.Length; i++)
{
var p = parameters[i];
var a = arguments[i];

if (a.IsNonCopyable() && !p.IsNonCopyable())
oc.ReportDiagnostic(Error(op.Syntax, rule, a.Name));
}
}
}

private static void CheckInstanceReadonly(in OperationAnalysisContext oc, IOperation instance, DiagnosticDescriptor rule)
{
if (instance == null) return;

var t = instance.Type;
if (!t.IsNonCopyable()) return;

if (IsInstanceReadonly(instance))
{
oc.ReportDiagnostic(Error(instance.Syntax, rule, t.Name));
}
}

private static Diagnostic Error(SyntaxNode at, DiagnosticDescriptor rule, string name = null)
=> name is null
? Diagnostic.Create(rule, at.GetLocation())
: Diagnostic.Create(rule, at.GetLocation(), name);

private static bool IsInstanceReadonly(IOperation instance)
{
bool isReadOnly = false;
switch (instance)
{
case IFieldReferenceOperation r:
isReadOnly = r.Field.IsReadOnly;
break;
case ILocalReferenceOperation r:
isReadOnly = r.Local.RefKind == RefKind.In;
break;
case IParameterReferenceOperation r:
isReadOnly = r.Parameter.RefKind == RefKind.In;
break;
}

return isReadOnly;
}

private static bool HasNonCopyableParameter(IMethodSymbol m)
{
foreach (var p in m.Parameters)
{
if(p.RefKind == RefKind.None)
{
if (p.Type.IsNonCopyable()) return true;
}
}
return false;
}

private static void CheckCopyability(in OperationAnalysisContext oc, IOperation v, DiagnosticDescriptor rule)
{
var t = v.Type;
if (!t.IsNonCopyable()) return;
if (v.CanCopy()) return;
oc.ReportDiagnostic(Error(v.Syntax, rule, t.Name));
}
}
}
Loading

[8]ページ先頭

©2009-2025 Movatter.jp