我正在阅读lifetime safety core guidelines paper,并渴望在实践中尝试使用using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
namespace IssueConsoleTemplate
{
//
// EF Core Entities:
//
public sealed class SearchContact
{
public Guid IdContact { get; set; }
public string FirstName { get; set; }
public IEnumerable<SearchContactsNumber> Numbers { get; set; }
}
//
// JSON Entities:
//
public sealed class SearchContactsNumber
{
public Guid IdNumber { get; set; }
public string Type { get; set; }
public string Number { get; set; }
}
//
// DbContext:
//
public class Context : DbContext
{
public DbSet<SearchContact> SearchContacts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseMySql(
"server=127.0.0.1;port=3306;user=root;password=;database=So64741089",
b => b.ServerVersion("8.0.21-mysql")
.CharSetBehavior(CharSetBehavior.NeverAppend)
.UseMicrosoftJson()) // <-- needed when using the Microsoft JSON stack (System.Text.Json)
.UseLoggerFactory(
LoggerFactory.Create(
b => b
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SearchContact>(
entity =>
{
entity.HasKey(e => e.IdContact);
entity.Property(e => e.Numbers)
.HasColumnType("json"); // <-- simple way to serialize any property from/to JSON
});
}
}
internal class Program
{
private static void Main()
{
using var context = new Context();
SetupDatabase(context);
var searchContacts = context.SearchContacts
.FromSqlInterpolated($"CALL `SearchContacts`()")
.ToList();
Debug.Assert(searchContacts.Count == 1);
Debug.Assert(searchContacts[0].Numbers.Count() == 1);
Debug.Assert(searchContacts[0].Numbers.First().IdNumber == new Guid("481d2957-21da-11eb-a249-de3268ec1e72"));
}
private static void SetupDatabase(Context context)
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var connection = context.Database.GetDbConnection();
connection.Open();
using var command = connection.CreateCommand();
command.CommandText = @"CREATE PROCEDURE `SearchContacts`()
BEGIN
SELECT '34f8d20f-21da-11eb-a249-de3268ec1e72' as `IdContact`,
'Paul' as `FirstName`,
'[{""IdNumber"":""481d2957-21da-11eb-a249-de3268ec1e72"",""Type"":""Telephone"",""Number"":""+440001122333""}]' as `Numbers`;
END";
command.ExecuteNonQuery();
}
}
}
标志。首先,我写了以下简单示例:
-Wlifetime
它确实会发出一些警告,但是显然它们出现在stdlib中,并且与我的代码无关:
class Wrapper
{
public:
Wrapper(std::string s)
: str_(std::move(s))
{ }
const std::string& GetString() const
{
return str_;
}
private:
std::string str_;
};
const std::string& example() {
return Wrapper("abc").GetString();
}
(无论我写什么代码,这些警告仍然存在,因此我认为它们无关紧要)
我对代码中缺少警告感到惊讶。据我所知,返回的字符串的生存期应为In file included from <built-in>:1:
/opt/compiler-explorer/clang-cppx-trunk/include/experimental/meta:3233:38: warning: returning a pointer with points-to set (*(*this).m_first) where points-to set ((null), **this) is expected [-Wlifetime]
consteval iterator begin() const { return m_first; }
^~~~~~~~~~~~~~
/opt/compiler-explorer/clang-cppx-trunk/include/experimental/meta:3235:36: warning: returning a pointer with points-to set (*(*this).m_last) where points-to set ((null), **this) is expected [-Wlifetime]
consteval iterator end() const { return m_last; }
^~~~~~~~~~~~~
/opt/compiler-explorer/clang-cppx-trunk/include/experimental/meta:3263:3: warning: returning a dangling pointer [-Wlifetime]
return range(reflection, pred);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/clang-cppx-trunk/include/experimental/meta:3276:10: note: in instantiation of function template specialization 'std::experimental::meta::v1::members_of<std::experimental::meta::v1::detail::always_true_fn>' requested here
return members_of(reflection, detail::always_true);
^
/opt/compiler-explorer/clang-cppx-trunk/include/experimental/meta:3263:10: note: it was never initialized here
return range(reflection, pred);
^~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/clang-cppx-trunk/include/experimental/meta:3281:3: warning: returning a dangling pointer [-Wlifetime]
return param_range(reflection);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/clang-cppx-trunk/include/experimental/meta:3281:10: note: it was never initialized here
return param_range(reflection);
^~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/clang-cppx-trunk/include/experimental/meta:3289:3: warning: returning a dangling pointer [-Wlifetime]
return __reflect(detail::query_get_begin, reflection);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/clang-cppx-trunk/include/experimental/meta:3289:10: note: it was never initialized here
return __reflect(detail::query_get_begin, reflection);
,因为它是Wrapper
的隐式参数(1.1.4:“默认情况下,我们假定函数返回的值源自其参数”)。我什至在类定义中添加了Wrapper::GetString
,但是没有运气。
Godbolt example with -Wlifetime
enabled
为什么我的代码没有产生警告,并且在这种情况下有什么方法可以使静态分析正常工作?