Continued updates for #184

* Reordering members
- Fields
- Constructors
- Properties
- EverythingElse
- NestedTypes

* Removing commented code
This commit is contained in:
Louis DeJardin 2015-09-02 20:08:54 -07:00
parent bf6a163f46
commit b25d2d9772
19 changed files with 309 additions and 297 deletions

View File

@ -15,16 +15,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
private static readonly Action<UvStreamHandle, int, Exception, object> _readCallback = ReadCallback;
private static readonly Func<UvStreamHandle, int, object, Libuv.uv_buf_t> _allocCallback = AllocCallback;
private static Libuv.uv_buf_t AllocCallback(UvStreamHandle handle, int suggestedSize, object state)
{
return ((Connection)state).OnAlloc(handle, suggestedSize);
}
private static void ReadCallback(UvStreamHandle handle, int nread, Exception error, object state)
{
((Connection)state).OnRead(handle, nread, error);
}
private readonly UvStreamHandle _socket;
private Frame _frame;
private long _connectionId = 0;
@ -48,6 +38,11 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
_socket.ReadStart(_allocCallback, _readCallback, this);
}
private static Libuv.uv_buf_t AllocCallback(UvStreamHandle handle, int suggestedSize, object state)
{
return ((Connection)state).OnAlloc(handle, suggestedSize);
}
private Libuv.uv_buf_t OnAlloc(UvStreamHandle handle, int suggestedSize)
{
return handle.Libuv.buf_init(
@ -55,6 +50,11 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
2048);
}
private static void ReadCallback(UvStreamHandle handle, int nread, Exception error, object state)
{
((Connection)state).OnRead(handle, nread, error);
}
private void OnRead(UvStreamHandle handle, int status, Exception error)
{
SocketInput.Unpin(status);
@ -117,13 +117,13 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
KestrelTrace.Log.ConnectionWriteFin(_connectionId, 0);
Thread.Post(
x =>
state =>
{
KestrelTrace.Log.ConnectionWriteFin(_connectionId, 1);
var self = (Connection)x;
var self = (Connection)state;
var shutdown = new UvShutdownReq();
shutdown.Init(self.Thread.Loop);
shutdown.Shutdown(self._socket, (req, status, state) =>
shutdown.Shutdown(self._socket, (req, status, _) =>
{
KestrelTrace.Log.ConnectionWriteFin(_connectionId, 1);
req.Dispose();
@ -140,7 +140,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
KestrelTrace.Log.ConnectionKeepAlive(_connectionId);
_frame = new Frame(this);
Thread.Post(
x => ((Frame)x).Consume(),
state => ((Frame)state).Consume(),
_frame);
break;
case ProduceEndType.SocketDisconnect:
@ -152,10 +152,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
KestrelTrace.Log.ConnectionDisconnect(_connectionId);
Thread.Post(
x =>
state =>
{
KestrelTrace.Log.ConnectionStop(_connectionId);
((UvHandle)x).Dispose();
((UvHandle)state).Dispose();
},
_socket);
break;

View File

@ -17,6 +17,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
public class Frame : FrameContext, IFrameControl
{
private static Encoding _ascii = Encoding.ASCII;
private static readonly ArraySegment<byte> _endChunkBytes = CreateAsciiByteArraySegment("\r\n");
private static readonly ArraySegment<byte> _endChunkedResponseBytes = CreateAsciiByteArraySegment("0\r\n\r\n");
private static readonly ArraySegment<byte> _continueBytes = CreateAsciiByteArraySegment("HTTP/1.1 100 Continue\r\n\r\n");
private Mode _mode;
private bool _responseStarted;
private bool _keepAlive;
@ -24,12 +28,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
private readonly FrameRequestHeaders _requestHeaders = new FrameRequestHeaders();
private readonly FrameResponseHeaders _responseHeaders = new FrameResponseHeaders();
/*
//IDictionary<string, object> _environment;
CancellationTokenSource _cts = new CancellationTokenSource();
*/
private List<KeyValuePair<Func<object, Task>, object>> _onStarting;
private List<KeyValuePair<Func<object, Task>, object>> _onCompleted;
private object _onStartingSync = new Object();
@ -64,18 +62,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
get { return _responseStarted; }
}
/*
public bool LocalIntakeFin
{
get
{
return _mode == Mode.MessageBody
? _messageBody.LocalIntakeFin
: _mode == Mode.Terminated;
}
}
*/
public void Consume()
{
var input = SocketInput;
@ -131,7 +117,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
break;
}
//var resumeBody = HandleExpectContinue(callback);
_mode = Mode.MessageBody;
Execute();
break;
@ -298,9 +283,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
immediate: false);
}
private static readonly ArraySegment<byte> _endChunkBytes = CreateAsciiByteArraySegment("\r\n");
private static readonly ArraySegment<byte> _endChunkedResponseBytes = CreateAsciiByteArraySegment("0\r\n\r\n");
private void WriteChunkSuffix()
{
SocketOutput.Write(_endChunkBytes,
@ -333,13 +315,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
_keepAlive = false;
ProduceStart();
// NOTE: needs changes
//_upgradeTask = callback(_callContext);
}
private static readonly ArraySegment<byte> _continueBytes = CreateAsciiByteArraySegment("HTTP/1.1 100 Continue\r\n\r\n");
private static ArraySegment<byte> CreateAsciiByteArraySegment(string text)
{
var bytes = Encoding.ASCII.GetBytes(text);
@ -380,13 +357,13 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
var responseHeader = CreateResponseHeader(status, appCompleted, ResponseHeaders);
SocketOutput.Write(
responseHeader.Item1,
(error, x) =>
(error, state) =>
{
if (error != null)
{
Trace.WriteLine("ProduceStart " + error.ToString());
}
((IDisposable)x).Dispose();
((IDisposable)state).Dispose();
},
responseHeader.Item2,
immediate: immediate);

View File

@ -21,6 +21,82 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
_responseStream = responseStream;
}
public override bool CanRead
{
get
{
return _requestStream.CanRead;
}
}
public override bool CanSeek
{
get
{
return _requestStream.CanSeek;
}
}
public override bool CanTimeout
{
get
{
return _responseStream.CanTimeout || _requestStream.CanTimeout;
}
}
public override bool CanWrite
{
get
{
return _responseStream.CanWrite;
}
}
public override long Length
{
get
{
return _requestStream.Length;
}
}
public override long Position
{
get
{
return _requestStream.Position;
}
set
{
_requestStream.Position = value;
}
}
public override int ReadTimeout
{
get
{
return _requestStream.ReadTimeout;
}
set
{
_requestStream.ReadTimeout = value;
}
}
public override int WriteTimeout
{
get
{
return _responseStream.WriteTimeout;
}
set
{
_responseStream.WriteTimeout = value;
}
}
#if DNX451
public override void Close()
{
@ -116,81 +192,5 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
_responseStream.WriteByte(value);
}
public override bool CanRead
{
get
{
return _requestStream.CanRead;
}
}
public override bool CanSeek
{
get
{
return _requestStream.CanSeek;
}
}
public override bool CanTimeout
{
get
{
return _responseStream.CanTimeout || _requestStream.CanTimeout;
}
}
public override bool CanWrite
{
get
{
return _responseStream.CanWrite;
}
}
public override long Length
{
get
{
return _requestStream.Length;
}
}
public override long Position
{
get
{
return _requestStream.Position;
}
set
{
_requestStream.Position = value;
}
}
public override int ReadTimeout
{
get
{
return _requestStream.ReadTimeout;
}
set
{
_requestStream.ReadTimeout = value;
}
}
public override int WriteTimeout
{
get
{
return _responseStream.WriteTimeout;
}
set
{
_responseStream.WriteTimeout = value;
}
}
}
}

View File

@ -15,6 +15,27 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
protected Dictionary<string, StringValues> Unknown => MaybeUnknown ?? (MaybeUnknown = new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase));
StringValues IDictionary<string, StringValues>.this[string key]
{
get
{
return GetValueFast(key);
}
set
{
SetValueFast(key, value);
}
}
int ICollection<KeyValuePair<string, StringValues>>.Count => GetCountFast();
bool ICollection<KeyValuePair<string, StringValues>>.IsReadOnly => false;
ICollection<string> IDictionary<string, StringValues>.Keys => ((IDictionary<string, StringValues>)this).Select(pair => pair.Key).ToList();
ICollection<StringValues> IDictionary<string, StringValues>.Values => ((IDictionary<string, StringValues>)this).Select(pair => pair.Value).ToList();
protected static StringValues AppendValue(StringValues existing, string append)
{
return StringValues.Concat(existing, append);
@ -47,28 +68,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
protected virtual IEnumerator<KeyValuePair<string, StringValues>> GetEnumeratorFast()
{ throw new NotImplementedException(); }
StringValues IDictionary<string, StringValues>.this[string key]
{
get
{
return GetValueFast(key);
}
set
{
SetValueFast(key, value);
}
}
int ICollection<KeyValuePair<string, StringValues>>.Count => GetCountFast();
bool ICollection<KeyValuePair<string, StringValues>>.IsReadOnly => false;
ICollection<string> IDictionary<string, StringValues>.Keys => ((IDictionary<string, StringValues>)this).Select(x => x.Key).ToList();
ICollection<StringValues> IDictionary<string, StringValues>.Values => ((IDictionary<string, StringValues>)this).Select(x => x.Value).ToList();
void ICollection<KeyValuePair<string, StringValues>>.Add(KeyValuePair<string, StringValues> item)
{
AddValueFast(item.Key, item.Value);

View File

@ -12,15 +12,27 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
private readonly MessageBody _body;
//int _readLength;
//bool _readFin;
//Exception _readError;
public FrameRequestStream(MessageBody body)
{
_body = body;
}
public override bool CanRead { get { return true; } }
public override bool CanSeek { get { return false; } }
public override bool CanWrite { get { return false; } }
public override long Length
{
get
{
throw new NotImplementedException();
}
}
public override long Position { get; set; }
public override void Flush()
{
throw new NotImplementedException();
@ -67,20 +79,20 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
var tcs = new TaskCompletionSource<int>(state);
var task = _body.ReadAsync(new ArraySegment<byte>(buffer, offset, count));
task.ContinueWith((t, x) =>
task.ContinueWith((task2, state2) =>
{
var tcs2 = (TaskCompletionSource<int>)x;
if (t.IsCanceled)
var tcs2 = (TaskCompletionSource<int>)state2;
if (task2.IsCanceled)
{
tcs2.SetCanceled();
}
else if (t.IsFaulted)
else if (task2.IsFaulted)
{
tcs2.SetException(t.Exception);
tcs2.SetException(task2.Exception);
}
else
{
tcs2.SetResult(t.Result);
tcs2.SetResult(task2.Result);
}
}, tcs);
return tcs.Task;
@ -90,21 +102,5 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
throw new NotImplementedException();
}
public override bool CanRead { get { return true; } }
public override bool CanSeek { get { return false; } }
public override bool CanWrite { get { return false; } }
public override long Length
{
get
{
throw new NotImplementedException();
}
}
public override long Position { get; set; }
}
}

View File

@ -17,9 +17,25 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
_context = context;
}
public override bool CanRead => false;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Length
{
get
{
throw new NotImplementedException();
}
}
public override long Position { get; set; }
public override void Flush()
{
//_write(default(ArraySegment<byte>), null);
FlushAsync(CancellationToken.None).Wait();
}
public override Task FlushAsync(CancellationToken cancellationToken)
@ -83,39 +99,5 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
tcs);
return tcs.Task;
}
public override bool CanRead
{
get
{
return false;
}
}
public override bool CanSeek
{
get
{
return false;
}
}
public override bool CanWrite
{
get
{
return true;
}
}
public override long Length
{
get
{
throw new NotImplementedException();
}
}
public override long Position { get; set; }
}
}

View File

@ -13,25 +13,13 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
/// </summary>
public abstract class Listener : ListenerContext, IDisposable
{
protected UvStreamHandle ListenSocket { get; private set; }
protected static void ConnectionCallback(UvStreamHandle stream, int status, Exception error, object state)
{
if (error != null)
{
Trace.WriteLine("Listener.ConnectionCallback " + error.ToString());
}
else
{
((Listener)state).OnConnection(stream, status);
}
}
protected Listener(IMemoryPool memory)
{
Memory = memory;
}
protected UvStreamHandle ListenSocket { get; private set; }
public Task StartAsync(
string scheme,
string host,
@ -63,6 +51,18 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
/// </summary>
protected abstract UvStreamHandle CreateListenSocket(string host, int port);
protected static void ConnectionCallback(UvStreamHandle stream, int status, Exception error, object state)
{
if (error != null)
{
Trace.WriteLine("Listener.ConnectionCallback " + error.ToString());
}
else
{
((Listener)state).OnConnection(stream, status);
}
}
/// <summary>
/// Handles an incoming connection
/// </summary>

View File

@ -15,8 +15,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
/// </summary>
abstract public class ListenerPrimary : Listener
{
UvPipeHandle ListenPipe { get; set; }
private List<UvPipeHandle> _dispatchPipes = new List<UvPipeHandle>();
private int _dispatchIndex;
private ArraySegment<ArraySegment<byte>> _1234 = new ArraySegment<ArraySegment<byte>>(new[] { new ArraySegment<byte>(new byte[] { 1, 2, 3, 4 }) });
@ -25,6 +23,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
}
UvPipeHandle ListenPipe { get; set; }
public async Task StartAsync(
string pipeName,
string scheme,

View File

@ -15,13 +15,13 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
/// </summary>
public abstract class ListenerSecondary : ListenerContext, IDisposable
{
UvPipeHandle DispatchPipe { get; set; }
protected ListenerSecondary(IMemoryPool memory)
{
Memory = memory;
}
UvPipeHandle DispatchPipe { get; set; }
public Task StartAsync(
string pipeName,
KestrelThread thread,

View File

@ -23,14 +23,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
private readonly Encoder _encoder;
public ArraySegment<byte> Buffer
{
get
{
return new ArraySegment<byte>(_dataArray, 0, _dataEnd);
}
}
public MemoryPoolTextWriter(IMemoryPool memory)
{
_memory = memory;
@ -39,6 +31,14 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
_encoder = Encoding.UTF8.GetEncoder();
}
public ArraySegment<byte> Buffer
{
get
{
return new ArraySegment<byte>(_dataArray, 0, _dataEnd);
}
}
public override Encoding Encoding
{
get

View File

@ -9,12 +9,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
public abstract class MessageBody : MessageBodyExchanger
{
public bool RequestKeepAlive { get; protected set; }
protected MessageBody(FrameContext context) : base(context)
{
}
public bool RequestKeepAlive { get; protected set; }
public void Intake(int count)
{
Transfer(count, false);

View File

@ -216,14 +216,14 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
private class WriteContext
{
public SocketOutput Self;
public Queue<ArraySegment<byte>> Buffers;
public WriteContext(SocketOutput self)
{
Self = self;
Buffers = new Queue<ArraySegment<byte>>();
}
public SocketOutput Self;
public Queue<ArraySegment<byte>> Buffers;
}
}
}

View File

@ -11,6 +11,7 @@ namespace Microsoft.AspNet.Server.Kestrel
public class Disposable : IDisposable
{
private Action _dispose;
private bool disposedValue = false; // To detect redundant calls
public Disposable(Action dispose)
{
@ -18,7 +19,6 @@ namespace Microsoft.AspNet.Server.Kestrel
}
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{

View File

@ -16,6 +16,7 @@ namespace Microsoft.AspNet.Server.Kestrel
/// </summary>
public class KestrelThread
{
private static Action<object, object> _objectCallback = (cb, obj) => ((Action<object>)cb).Invoke(obj);
private KestrelEngine _engine;
private Thread _thread;
private UvLoopHandle _loop;
@ -102,7 +103,21 @@ namespace Microsoft.AspNet.Server.Kestrel
{
lock (_workSync)
{
_workAdding.Enqueue(new Work { Callback = callback, State = state });
_workAdding.Enqueue(new Work { Callback1 = _objectCallback, Callback2 = callback, State = state });
}
_post.Send();
}
public void Post<T>(Action<T> callback, T state)
{
lock (_workSync)
{
_workAdding.Enqueue(new Work
{
Callback1 = (state1, state2) => ((Action<T>)state1).Invoke((T)state2),
Callback2 = callback,
State = state
});
}
_post.Send();
}
@ -112,7 +127,30 @@ namespace Microsoft.AspNet.Server.Kestrel
var tcs = new TaskCompletionSource<int>();
lock (_workSync)
{
_workAdding.Enqueue(new Work { Callback = callback, State = state, Completion = tcs });
_workAdding.Enqueue(new Work
{
Callback1 = _objectCallback,
Callback2 = callback,
State = state,
Completion = tcs
});
}
_post.Send();
return tcs.Task;
}
public Task PostAsync<T>(Action<T> callback, T state)
{
var tcs = new TaskCompletionSource<int>();
lock (_workSync)
{
_workAdding.Enqueue(new Work
{
Callback1 = (state1, state2) => ((Action<T>)state1).Invoke((T)state2),
Callback2 = callback,
State = state,
Completion = tcs
});
}
_post.Send();
return tcs.Task;
@ -212,7 +250,7 @@ namespace Microsoft.AspNet.Server.Kestrel
var work = queue.Dequeue();
try
{
work.Callback(work.State);
work.Callback1(work.Callback2, work.State);
if (work.Completion != null)
{
ThreadPool.QueueUserWorkItem(
@ -261,7 +299,8 @@ namespace Microsoft.AspNet.Server.Kestrel
private struct Work
{
public Action<object> Callback;
public Action<object, object> Callback1;
public object Callback2;
public object State;
public TaskCompletionSource<int> Completion;
}

View File

@ -14,6 +14,10 @@ namespace Microsoft.AspNet.Server.Kestrel
Addresses = new List<ServerAddress>();
}
public IList<ServerAddress> Addresses { get; private set; }
public int ThreadCount { get; set; }
public void Initialize(IConfiguration configuration)
{
var urls = configuration["server.urls"];
@ -30,9 +34,5 @@ namespace Microsoft.AspNet.Server.Kestrel
}
}
}
public IList<ServerAddress> Addresses { get; private set; }
public int ThreadCount { get; set; }
}
}

View File

@ -9,6 +9,13 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
{
public class Libuv
{
public bool IsWindows;
public bool IsDarwin;
public Func<string, IntPtr> LoadLibrary;
public Func<IntPtr, bool> FreeLibrary;
public Func<IntPtr, string, IntPtr> GetProcAddress;
public Libuv()
{
IsWindows = PlatformApis.IsWindows();
@ -18,13 +25,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
}
}
public bool IsWindows;
public bool IsDarwin;
public Func<string, IntPtr> LoadLibrary;
public Func<IntPtr, bool> FreeLibrary;
public Func<IntPtr, string, IntPtr> GetProcAddress;
public void Load(string dllToLoad)
{
PlatformApis.Apply(this);
@ -395,16 +395,19 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
public struct sockaddr
{
public sockaddr(long ignored) { x3 = x0 = x1 = x2 = x3 = 0; }
private long x0;
private long x1;
private long x2;
private long x3;
public sockaddr(long ignored) { x3 = x0 = x1 = x2 = x3 = 0; }
}
public struct uv_buf_t
{
public IntPtr x0;
public IntPtr x1;
public uv_buf_t(IntPtr memory, int len, bool IsWindows)
{
if (IsWindows)
@ -418,9 +421,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
x1 = (IntPtr)len;
}
}
public IntPtr x0;
public IntPtr x1;
}
public enum HandleType
@ -456,10 +456,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
WORK,
GETADDRINFO,
GETNAMEINFO,
}
//int handle_size_async;
//int handle_size_tcp;
//int req_size_write;
//int req_size_shutdown;
}
}
}

View File

@ -26,13 +26,6 @@ namespace Microsoft.AspNet.Server.Kestrel
PopulateFeatures();
}
private void PopulateFeatures()
{
_features[typeof(IHttpRequestFeature)] = this;
_features[typeof(IHttpResponseFeature)] = this;
_features[typeof(IHttpUpgradeFeature)] = this;
}
internal IFeatureCollection Features
{
get { return _features; }
@ -199,16 +192,6 @@ namespace Microsoft.AspNet.Server.Kestrel
get { return _frame.HasResponseStarted; }
}
void IHttpResponseFeature.OnStarting(Func<object, Task> callback, object state)
{
_frame.OnStarting(callback, state);
}
void IHttpResponseFeature.OnCompleted(Func<object, Task> callback, object state)
{
_frame.OnCompleted(callback, state);
}
bool IHttpUpgradeFeature.IsUpgradableRequest
{
get
@ -222,6 +205,23 @@ namespace Microsoft.AspNet.Server.Kestrel
}
}
private void PopulateFeatures()
{
_features[typeof(IHttpRequestFeature)] = this;
_features[typeof(IHttpResponseFeature)] = this;
_features[typeof(IHttpUpgradeFeature)] = this;
}
void IHttpResponseFeature.OnStarting(Func<object, Task> callback, object state)
{
_frame.OnStarting(callback, state);
}
void IHttpResponseFeature.OnCompleted(Func<object, Task> callback, object state)
{
_frame.OnCompleted(callback, state);
}
Task<Stream> IHttpUpgradeFeature.UpgradeAsync()
{
_frame.StatusCode = 101;

View File

@ -0,0 +1,6 @@
namespace Microsoft.AspNet.Server.Kestrel
{
public class StandardsPoliceCompileModule : Microsoft.StandardsPolice.StandardsPoliceCompileModule
{
}
}

View File

@ -117,21 +117,16 @@ namespace Microsoft.StandardsPolice
}
}
enum ClassZone
{
Ignored,
BeforeStart,
Fields,
Constructors,
Properties,
OtherThings,
NestedTypes,
AfterEnd
}
private static void RuleMembersAreInCorrectOrder(IList<Diagnostic> diagnostics, INamedTypeSymbol typeSymbol, Func<ISymbol, ClassZone> mapZone)
{
if (typeSymbol.Locations.Length >= 2 || typeSymbol.Name == "Libuv")
{
// Don't apply to partial classes. All members are enumerated, but are not merged by zone order.
return;
}
var currentZone = ClassZone.BeforeStart;
var currentZoneExample = default(ISymbol);
foreach (var member in typeSymbol.GetMembers())
{
var memberZone = mapZone(member);
@ -139,9 +134,10 @@ namespace Microsoft.StandardsPolice
{
continue;
}
if (currentZone < memberZone)
if (currentZone <= memberZone)
{
currentZone = memberZone;
currentZoneExample = member;
}
if (memberZone >= ClassZone.OtherThings)
{
@ -152,26 +148,29 @@ namespace Microsoft.StandardsPolice
if (member.Locations.Count() == 1)
{
diagnostics.Add(Diagnostic.Create(
"SP1003", "StandardsPolice", $"{memberZone} like {typeSymbol.Name}::{member.Name} shouldn't be after {currentZone}",
"SP1003", "StandardsPolice", $"{memberZone} like {typeSymbol.Name}::{member.Name} shouldn't be after {currentZone} like {currentZoneExample.Name}",
DiagnosticSeverity.Warning,
DiagnosticSeverity.Warning,
false,
3,
location: member.Locations.Single()));
location: member.Locations.Single(),
additionalLocations: currentZoneExample.Locations));
}
}
}
currentZone = ClassZone.AfterEnd;
foreach (var member in typeSymbol.GetMembers())
currentZoneExample = null;
foreach (var member in typeSymbol.GetMembers().Reverse())
{
var memberZone = mapZone(member);
if (memberZone == ClassZone.Ignored)
{
continue;
}
if (currentZone > memberZone)
if (currentZone >= memberZone)
{
currentZone = memberZone;
currentZoneExample = member;
}
if (memberZone <= ClassZone.OtherThings)
{
@ -182,12 +181,13 @@ namespace Microsoft.StandardsPolice
if (member.Locations.Count() == 1)
{
diagnostics.Add(Diagnostic.Create(
"SP1003", "StandardsPolice", $"{memberZone} like {typeSymbol.Name}::{member.Name} shouldn't be before {currentZone}",
"SP1003", "StandardsPolice", $"{memberZone} like {typeSymbol.Name}::{member.Name} shouldn't be before {currentZone} like {currentZoneExample.Name}",
DiagnosticSeverity.Warning,
DiagnosticSeverity.Warning,
false,
3,
location: member.Locations.Single()));
location: member.Locations.Single(),
additionalLocations: currentZoneExample.Locations));
}
}
}
@ -211,6 +211,11 @@ namespace Microsoft.StandardsPolice
{
return ClassZone.Constructors;
}
if (method.MethodKind == MethodKind.PropertyGet ||
method.MethodKind == MethodKind.PropertySet)
{
return ClassZone.Properties;
}
}
if (member.Kind == SymbolKind.Property)
{
@ -232,5 +237,17 @@ namespace Microsoft.StandardsPolice
public void AfterCompile(AfterCompileContext context)
{
}
enum ClassZone
{
Ignored,
BeforeStart,
Fields,
Constructors,
Properties,
OtherThings,
NestedTypes,
AfterEnd
}
}
}