Skip to content

Commit 8d251e5

Browse files
committed
Merge branch 'master' into TS37
# Conflicts: # Signum.React/Scripts/Frames/FrameModal.tsx # Signum.React/Scripts/Lines/EntityCheckboxList.tsx # Signum.React/Scripts/Lines/EntityTable.tsx # Signum.React/Scripts/Operations/EntityOperations.tsx # Signum.React/Scripts/SearchControl/ColumnEditor.tsx # Signum.React/Scripts/SearchControl/SearchControl.tsx # Signum.React/Signum.React.csproj
2 parents 3119a20 + 599048f commit 8d251e5

File tree

78 files changed

+851
-610
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+851
-610
lines changed

Signum.Analyzer/Signum.Analyzer.Test/AutoExpressionFieldTest.cs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,14 @@ public void AutoExpressionNoLambda()
125125
public static int OperationLogs(this Entity e) => As.Expression<int>(null);");
126126
}
127127

128+
[TestMethod]
129+
public void AutoExpressionImplicitCasting()
130+
{
131+
TestDiagnostic("the call to As.Expression returns 'PrimaryKey' but is implicitly converted to 'int?'", @"
132+
[AutoExpressionField]
133+
public static int? OperationLogs(Entity e) => As.Expression(() => e.Id);", assertErrors: false);
134+
}
135+
128136
[TestMethod]
129137
public void AutoExpressionCorrectWithError()
130138
{
@@ -193,11 +201,9 @@ public void AutoExpressionFixStatic()
193201
public void AutoExpressionFixInstanceProperty()
194202
{
195203
TestCodeFix(@"
196-
197204
[AutoExpressionField]
198205
public string IdToStr => this.ToString();",
199206
@"
200-
201207
[AutoExpressionField]
202208
public string IdToStr => As.Expression(() => this.ToString());", staticClass: false);
203209
}
@@ -206,11 +212,9 @@ public void AutoExpressionFixInstanceProperty()
206212
public void AutoExpressionFixInstancePropertyStatement()
207213
{
208214
TestCodeFix(@"
209-
210215
[AutoExpressionField]
211216
public string IdToStr { get { return ToString(); } }",
212217
@"
213-
214218
[AutoExpressionField]
215219
public string IdToStr { get { return As.Expression(() => ToString()); } }", staticClass: false);
216220
}
@@ -220,11 +224,9 @@ public void AutoExpressionFixInstancePropertyStatement()
220224
public void AutoExpressionFixInstanceMethodStatement()
221225
{
222226
TestCodeFix(@"
223-
224227
[AutoExpressionField]
225228
public string GetId() { return ToString(); }",
226229
@"
227-
228230
[AutoExpressionField]
229231
public string GetId() { return As.Expression(() => ToString()); }", staticClass: false);
230232
}
@@ -233,17 +235,26 @@ public void AutoExpressionFixInstanceMethodStatement()
233235
public void AutoExpressionFixInstanceMethodStatementTrivia()
234236
{
235237
TestCodeFix(@"
236-
237238
[AutoExpressionField]
238239
public string GetId() =>
239240
ToString();",
240241
@"
241-
242242
[AutoExpressionField]
243243
public string GetId() =>
244244
As.Expression(() => ToString());", staticClass: false);
245245
}
246246

247+
[TestMethod]
248+
public void AutoExpressionExplicitCast()
249+
{
250+
TestCodeFix(@"
251+
[AutoExpressionField]
252+
public int? GetId() => As.Expression(()=>3);",
253+
@"
254+
[AutoExpressionField]
255+
public int? GetId() => As.Expression(()=> (int?)3);", staticClass: false);
256+
}
257+
247258
private void TestCodeFix(string initial, string final, bool staticClass = true)
248259
{
249260
VerifyCSharpFix(

Signum.Analyzer/Signum.Analyzer.Test/ExpressionFieldTest.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ public void ExpressionExplicitCorrect()
4444
public static int OperationLogs(this Entity e) => 0;");
4545
}
4646

47+
[TestMethod]
48+
public void ExpressionExplicitNotCorrectNullable()
49+
{
50+
TestDiagnostic("type of 'MyExpression' should be 'Expression<Func<Entity, string?>>'", @"
51+
static Expression<Func<Entity, string>> MyExpression;
52+
[ExpressionField(""MyExpression"")]
53+
public static string? OperationLogs(this Entity e) => """";");
54+
}
55+
4756
[TestMethod]
4857
public void ExpressionExplicitCorrectNullable()
4958
{

Signum.Analyzer/Signum.Analyzer.Test/Signum.Analyzer.Test.csproj

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>netcoreapp2.2</TargetFramework>
4+
<TargetFramework>netcoreapp3.0</TargetFramework>
55
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
66
<Platforms>AnyCPU;x64</Platforms>
7-
7+
<NoWarn>NU1201</NoWarn>
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="2.9.4">
11+
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="2.9.7">
1212
<PrivateAssets>all</PrivateAssets>
1313
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
1414
</PackageReference>
15-
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.2.1" />
16-
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.2.1" />
17-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
18-
<PackageReference Include="MSTest.TestAdapter" Version="1.4.0" />
19-
<PackageReference Include="MSTest.TestFramework" Version="1.4.0" />
15+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.3.1" />
16+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.3.1" />
17+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
18+
<PackageReference Include="MSTest.TestAdapter" Version="2.0.0" />
19+
<PackageReference Include="MSTest.TestFramework" Version="2.0.0" />
2020
</ItemGroup>
2121

2222
<ItemGroup>

Signum.Analyzer/Signum.Analyzer/AutoExpressionFieldAnalyzer.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,18 @@ static void AnalyzeAttributeSymbol(SyntaxNodeAnalysisContext context)
9191
return;
9292
}
9393

94+
var type = context.SemanticModel.GetTypeInfo(inv);
95+
96+
if(!type.ConvertedNullability.Equals(type.Nullability) ||
97+
!type.Type.Equals(type.ConvertedType, SymbolEqualityComparer.IncludeNullability))
98+
{
99+
var position = member.GetLocation().SourceSpan.Start;
100+
var current = type.Type.ToMinimalDisplayString(context.SemanticModel, type.Nullability.FlowState, position);
101+
var converted = type.ConvertedType.ToMinimalDisplayString(context.SemanticModel, type.ConvertedNullability.FlowState, position);
102+
103+
Diagnostic(context, ident, att.GetLocation(), $"the call to As.Expression returns '{current}' but is implicitly converted to '{converted}'", fixable: true, explicitConvert: converted);
104+
return;
105+
}
94106
}
95107
catch (Exception e)
96108
{
@@ -176,9 +188,12 @@ internal static ExpressionSyntax OnlyReturn(SyntaxNodeAnalysisContext context, s
176188
return ret.Expression;
177189
}
178190

179-
private static void Diagnostic(SyntaxNodeAnalysisContext context, string identifier, Location location, string error, bool fixable = false)
191+
private static void Diagnostic(SyntaxNodeAnalysisContext context, string identifier, Location location, string error, bool fixable = false, string explicitConvert = null)
180192
{
181193
var properties = ImmutableDictionary<string, string>.Empty.Add("fixable", fixable.ToString());
194+
if (explicitConvert != null)
195+
properties = properties.Add("explicitConvert", explicitConvert);
196+
182197
var diagnostic = Microsoft.CodeAnalysis.Diagnostic.Create(Rule, location, properties, identifier, error);
183198

184199
context.ReportDiagnostic(diagnostic);

Signum.Analyzer/Signum.Analyzer/AutoExpressionFieldFixProvider.cs

Lines changed: 32 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,40 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
4141

4242
if (diagnostic.Properties["fixable"] == "True")
4343
{
44-
context.RegisterCodeFix(
45-
CodeAction.Create("Add As.Expression(() => )", c => AddAsExpression(context.Document, declaration, c), "AddAsExpression"),
44+
if (diagnostic.Properties.TryGetValue("explicitConvert", out var newType))
45+
{
46+
context.RegisterCodeFix(
47+
CodeAction.Create($"Add Explicit Cast to '{newType}'", c => InsertExplicitCast(context.Document, declaration, c), "InsertExplicitCast"),
4648
diagnostic);
49+
}
50+
else
51+
{
52+
context.RegisterCodeFix(
53+
CodeAction.Create("Add As.Expression(() => )", c => AddAsExpression(context.Document, declaration, c), "AddAsExpression"),
54+
diagnostic);
55+
}
4756
}
4857
}
4958

59+
private async Task<Document> InsertExplicitCast(Document document, MemberDeclarationSyntax declaration, CancellationToken c)
60+
{
61+
var bodyExpression = GetSingleBody(declaration);
62+
63+
var invoke = (InvocationExpressionSyntax)bodyExpression;
64+
65+
var lambda = (LambdaExpressionSyntax)invoke.ArgumentList.Arguments[0].Expression;
66+
67+
var docRoot = await document.GetSyntaxRootAsync();
68+
69+
var type = declaration is MethodDeclarationSyntax ?
70+
((MethodDeclarationSyntax)declaration).ReturnType :
71+
((PropertyDeclarationSyntax)declaration).Type;
72+
73+
var newRoot = docRoot.ReplaceNode(lambda.Body, SyntaxFactory.CastExpression(type, (ExpressionSyntax)lambda.Body));
74+
75+
return document.WithSyntaxRoot(newRoot);
76+
}
77+
5078
private async Task<Document> AddAsExpression(Document document, MemberDeclarationSyntax declaration, CancellationToken c)
5179
{
5280
var typeSyntax = declaration.Ancestors().OfType<TypeDeclarationSyntax>().First();
@@ -69,9 +97,9 @@ private async Task<Document> AddAsExpression(Document document, MemberDeclaratio
6997

7098
var docRoot = await document.GetSyntaxRootAsync();
7199

72-
var newDoc = docRoot.ReplaceNode(bodyExpression, newBody);
100+
var newRoot = docRoot.ReplaceNode(bodyExpression, newBody);
73101

74-
return document.WithSyntaxRoot(newDoc);
102+
return document.WithSyntaxRoot(newRoot);
75103
}
76104

77105
private InvocationExpressionSyntax GetNewBody(ExpressionSyntax bodyExpression)
@@ -87,47 +115,6 @@ private InvocationExpressionSyntax GetNewBody(ExpressionSyntax bodyExpression)
87115
.NormalizeWhitespace();
88116
}
89117

90-
//private void MoveInitialTrivia(ref ExpressionSyntax bodyExpression, ref InvocationExpressionSyntax newDeclaration)
91-
//{
92-
// var leadingTrivia = newDeclaration.GetLeadingTrivia();
93-
94-
// if (!leadingTrivia.Any())
95-
// return;
96-
97-
// var last = leadingTrivia.Last();
98-
99-
// if (leadingTrivia.Any() && (SyntaxKind)last.RawKind == SyntaxKind.WhitespaceTrivia)
100-
// {
101-
// newField = newField.WithLeadingTrivia(leadingTrivia);
102-
103-
// newDeclaration = newDeclaration.WithLeadingTrivia(last);
104-
// }
105-
//}
106-
107-
public static GenericNameSyntax GetExpressionTypeSyntax(List<ParameterSyntax> parameterList, TypeSyntax returnType)
108-
{
109-
var funcType = SyntaxFactory.GenericName(SyntaxFactory.Identifier("Func"),
110-
SyntaxFactory.TypeArgumentList().AddArguments(parameterList.Select(a => a.Type).Concat(new[] { returnType }).ToArray()));
111-
112-
var expressionType = SyntaxFactory.GenericName(SyntaxFactory.Identifier("Expression"),
113-
SyntaxFactory.TypeArgumentList().AddArguments(funcType));
114-
return expressionType;
115-
}
116-
117-
118-
public static List<ParameterSyntax> GetParameters(MemberDeclarationSyntax declaration, INamedTypeSymbol type, ISymbol symbol)
119-
{
120-
var parameterList = declaration is MethodDeclarationSyntax ?
121-
((MethodDeclarationSyntax)declaration).ParameterList.Parameters.ToList() :
122-
new List<ParameterSyntax>();
123-
124-
if (!symbol.IsStatic)
125-
parameterList.Insert(0, SyntaxFactory.Parameter(SyntaxFactory.Identifier("@this")).WithType(SyntaxFactory.IdentifierName(type.Name)));
126-
127-
return parameterList;
128-
}
129-
130-
131118
public static ExpressionSyntax GetSingleBody(MemberDeclarationSyntax member)
132119
{
133120
if (member is MethodDeclarationSyntax)

Signum.Analyzer/Signum.Analyzer/ExpressionFieldAnalyzer.cs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -96,17 +96,12 @@ static void AnalyzeAttributeSymbol(SyntaxNodeAnalysisContext context)
9696

9797
var expressionType = GetExpressionType(memberSymbol, context.SemanticModel);
9898

99-
if (!expressionType.Equals(fieldSymbol.Type))
99+
if (!expressionType.Equals(fieldSymbol.Type, SymbolEqualityComparer.IncludeNullability))
100100
{
101-
if (!expressionType.ToString().Replace("?", "").Equals(
102-
fieldSymbol.Type.ToString().Replace("?", ""))) // Till there is an API to express nullability
103-
{
104-
var minimalParts = expressionType.ToMinimalDisplayString(context.SemanticModel, member.GetLocation().SourceSpan.Start);
105-
Diagnostic(context, ident, att.GetLocation(), string.Format("type of '{0}' should be '{1}'", fieldName, minimalParts));
106-
return;
107-
}
101+
var minimalParts = expressionType.ToMinimalDisplayString(context.SemanticModel, member.GetLocation().SourceSpan.Start);
102+
Diagnostic(context, ident, att.GetLocation(), string.Format("type of '{0}' should be '{1}'", fieldName, minimalParts));
103+
return;
108104
}
109-
110105
}
111106
catch (Exception e)
112107
{
@@ -116,19 +111,27 @@ static void AnalyzeAttributeSymbol(SyntaxNodeAnalysisContext context)
116111

117112
private static INamedTypeSymbol GetExpressionType(ISymbol memberSymbol, SemanticModel sm)
118113
{
119-
var parameters = memberSymbol is IMethodSymbol ? ((IMethodSymbol)memberSymbol).Parameters.Select(p => p.Type).ToList() : new List<ITypeSymbol>();
114+
var parameters = memberSymbol is IMethodSymbol ? ((IMethodSymbol)memberSymbol).Parameters.Select(p => (p.Type, p.NullableAnnotation)).ToList() : new List<(ITypeSymbol, NullableAnnotation)>();
120115

121116
if (!memberSymbol.IsStatic)
122-
parameters.Insert(0, (ITypeSymbol)memberSymbol.ContainingSymbol);
117+
parameters.Insert(0, ((ITypeSymbol)memberSymbol.ContainingSymbol, NullableAnnotation.NotAnnotated));
123118

124-
var returnType = memberSymbol is IMethodSymbol ? ((IMethodSymbol)memberSymbol).ReturnType : ((IPropertySymbol)memberSymbol).Type;
119+
var returnType = memberSymbol is IMethodSymbol mi ? (mi.ReturnType, mi.ReturnNullableAnnotation) :
120+
memberSymbol is IPropertySymbol pi ? (pi.Type, pi.NullableAnnotation) :
121+
throw new InvalidOperationException("Unexpected member");
125122

126123
parameters.Add(returnType);
127124

128125
var expression = sm.Compilation.GetTypeByMetadataName("System.Linq.Expressions.Expression`1");
129126
var func = sm.Compilation.GetTypeByMetadataName("System.Func`" + parameters.Count);
130127

131-
return expression.Construct(func.Construct(parameters.ToArray()));
128+
var funcConstruct = func.Construct(
129+
parameters.Select(a => a.Item1).ToImmutableArray(),
130+
parameters.Select(a => a.Item2).ToImmutableArray());
131+
132+
return expression.Construct(
133+
ImmutableArray.Create((ITypeSymbol)funcConstruct),
134+
ImmutableArray.Create(NullableAnnotation.NotAnnotated));
132135
}
133136

134137
public static ExpressionSyntax GetSingleBody(SyntaxNodeAnalysisContext context, string ident, AttributeSyntax att, MemberDeclarationSyntax member)

Signum.Analyzer/Signum.Analyzer/Signum.Analyzer.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
<PropertyGroup>
1111
<PackageId>Signum.Analyzer</PackageId>
12-
<PackageVersion>2.4.5</PackageVersion>
12+
<PackageVersion>2.5.0</PackageVersion>
1313
<Authors>Olmo del Corral</Authors>
1414
<PackageProjectUrl>http://www.signumframework.com</PackageProjectUrl>
1515
<RepositoryUrl>https://github.com/signumsoftware/framework</RepositoryUrl>
@@ -19,14 +19,14 @@
1919
<PackageTags>Signum.Analyzer, analyzers</PackageTags>
2020
<NoPackageAnalysis>true</NoPackageAnalysis>
2121
<PackageLicenseUrl></PackageLicenseUrl>
22-
<Version>2.4.5</Version>
22+
<Version>2.5.0</Version>
2323
<PackageIconUrl>https://raw.githubusercontent.com/signumsoftware/framework/master/SignumLogo.png</PackageIconUrl>
2424
<PackageLicenseExpression>MIT</PackageLicenseExpression>
2525
</PropertyGroup>
2626

2727
<ItemGroup>
28-
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="2.9.4" PrivateAssets="all" />
29-
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.2.1" PrivateAssets="all" />
28+
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="2.9.7" PrivateAssets="all" />
29+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.3.1" PrivateAssets="all" />
3030
<PackageReference Update="NETStandard.Library" PrivateAssets="all" />
3131
</ItemGroup>
3232

Signum.Engine/Administrator.cs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ from c in t.Columns()
4444
Name = c.name,
4545
SqlDbType = SchemaSynchronizer.ToSqlDbType(c.Type()!.name),
4646
UserTypeName = null,
47-
Identity = c.is_identity,
47+
PrimaryKey = t.Indices().Any(i => i.is_primary_key && i.IndexColumns().Any(ic => ic.column_id == c.column_id)),
4848
Nullable = c.is_nullable,
4949
}).ToList();
5050

@@ -63,13 +63,11 @@ from c in t.Columns()
6363
private static string GenerateColumnCode(DiffColumn c)
6464
{
6565
var type = CodeGeneration.CodeGenerator.Entities.GetValueType(c);
66-
if (c.Nullable)
67-
type = type.Nullify();
68-
66+
6967
StringBuilder sb = new StringBuilder();
70-
if (c.Identity)
68+
if (c.PrimaryKey)
7169
sb.AppendLine("[ViewPrimaryKey]");
72-
sb.AppendLine($"public {type.TypeName()} {c.Name};");
70+
sb.AppendLine($"public {type.TypeName()}{(c.Nullable ? "?" : "")} {c.Name};");
7371
return sb.ToString();
7472
}
7573

@@ -107,6 +105,27 @@ public static void CreateTemporaryTable<T>()
107105
SqlBuilder.CreateTableSql(view).ExecuteNonQuery();
108106
}
109107

108+
public static IDisposable TemporaryTable<T>() where T : IView
109+
{
110+
CreateTemporaryTable<T>();
111+
112+
return new Disposable(() => DropTemporaryTable<T>());
113+
}
114+
115+
public static void DropTemporaryTable<T>()
116+
where T : IView
117+
{
118+
if (!Transaction.HasTransaction)
119+
throw new InvalidOperationException("You need to be inside of a transaction to create a Temporary table");
120+
121+
var view = Schema.Current.View<T>();
122+
123+
if (!view.Name.IsTemporal)
124+
throw new InvalidOperationException($"Temporary tables should start with # (i.e. #myTable). Consider using {nameof(TableNameAttribute)}");
125+
126+
SqlBuilder.DropTable(view.Name).ExecuteNonQuery();
127+
}
128+
110129
public static void CreateTemporaryIndex<T>(Expression<Func<T, object>> fields, bool unique = false)
111130
where T : IView
112131
{

0 commit comments

Comments
 (0)