tgjones / HlslTools

A Visual Studio extension that provides enhanced support for editing High Level Shading Language (HLSL) files
http://timjones.io/blog/archive/2016/04/25/hlsl-tools-for-visual-studio-v1.0-released
Other
568 stars 98 forks source link

InvalidCastException when adding function argument #83

Closed OndrejPetrzilka closed 7 years ago

OndrejPetrzilka commented 7 years ago

Happens every time when editing same piece of code. Adding function argument in the middle, the type of argument is struct.

Exact moment is when type name is pasted from clipboard

System.InvalidCastException occurred
  HResult=0x80004002
  Message=Unable to cast object of type 'ShaderTools.Hlsl.Syntax.SyntaxToken' to type 'ShaderTools.Hlsl.Syntax.ParameterSyntax'.
  Source=ShaderTools.Editor.VisualStudio
  StackTrace:
   at ShaderTools.Editor.VisualStudio.Hlsl.Util.SyntaxOutput.SyntaxExtensions.GetFunctionDescription(TypeSyntax returnType, SyntaxToken name, ParameterListSyntax parameterList, Boolean includeReturnType, Boolean includeParameterNames)
   at ShaderTools.Editor.VisualStudio.Hlsl.Navigation.NavigationTargetsVisitor.<VisitFunctionDefinition>d__14.MoveNext()
   at System.Linq.Enumerable.<SelectManyIterator>d__16`2.MoveNext()
   at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at ShaderTools.Editor.VisualStudio.Hlsl.Navigation.NavigationTargetsVisitor.<GetTargets>d__6.MoveNext()
   at System.Collections.Generic.List`1.InsertRange(Int32 index, IEnumerable`1 collection)
   at ShaderTools.Editor.VisualStudio.Hlsl.Navigation.EditorNavigationSource.<>c__DisplayClass5_0.<InvalidateTargets>b__0()
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at ShaderTools.Editor.VisualStudio.Hlsl.Navigation.EditorNavigationSource.<InvalidateTargets>d__5.MoveNext()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at ShaderTools.Editor.VisualStudio.Hlsl.Navigation.EditorNavigationSource.<>c__DisplayClass3_0.<<-ctor>b__1>d.MoveNext()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at ShaderTools.Editor.VisualStudio.Core.Util.ExceptionHelper.<TryCatchCancellation>d__0.MoveNext()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at ShaderTools.Editor.VisualStudio.Hlsl.Navigation.EditorNavigationSource.<<-ctor>b__3_0>d.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_1(Object state)
   at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
tgjones commented 7 years ago

I can't repro this - @OndrejPetrzilka, please could you include a minimal example here, with the text to paste, and position it should be pasted?

OndrejPetrzilka commented 7 years ago

Pasted text: EmitterState

Place: Almost at the bottom of the pasted code, marked with /* HERE*/, right after comma, before space

It can be easily reproduced, in case you need more info, happens in 100% cases.

struct EmitterState
{
    static const uint CountMask = 0x00ffffff;
    static const uint UpdatingMask = 0x01000000;
    static const uint StoppingMask = 0x02000000;
    static const uint NoAutoDeleteMask = 0x04000000;
    static const uint PreviousStoppingMask = 0x08000000;

    uint PackedValue;

    bool IsUpdating()
    {
        return GetFlag(PackedValue, UpdatingMask);
    }

    bool IsStopping()
    {
        return GetFlag(PackedValue, StoppingMask);
    }

    bool IsFirstFrame()
    {
        // First frame is when effect is not stopping and it was previously stopped or just started (!IsUpdating)
        return !IsStopping() && (!IsUpdating() || GetFlag(PackedValue, PreviousStoppingMask));
    }

    // Overrides IsStopping state in effect parameters (cannot override IsStopped)
    // Can be used to create custom end of the effect
    void OverrideIsStopping(bool isStopping)
    {
        PackedValue = SetFlag(PackedValue, StoppingMask, isStopping);
    }

    bool GetAutoDelete()
    {
        return !GetFlag(PackedValue, NoAutoDeleteMask);
    }

    // Enables or disabled auto-delete, enabled by default, when there are no alive particles, effect is stopped.
    void SetAutoDelete(bool enableAutoDelete)
    {
        PackedValue = SetFlag(PackedValue, NoAutoDeleteMask, !enableAutoDelete);
    }

    // Gets number of particles spawned next frame
    uint GetSpawnCount()
    {
        return (PackedValue & CountMask);
    }

    // Sets amount of particles to spawn next frame
    void Spawn(int particlesPerFrame)
    {
        PackedValue = (PackedValue & ~CountMask) | (particlesPerFrame & CountMask);
    }

    // Sets amount of particles to spawn on when it's first frame
    void SpawnOnce(int particleCount)
    {
        // IsUpdating is false during first update
        // It's also false when effect is stopped, but in such case, spawn count will be forced to 0
        Spawn(IsFirstFrame() ? particleCount : 0);
    }

    // Sets amount of particles to spawn per second
    void SpawnUniform(float particlesPerSecond)
    {
        Spawn(UniformSpawn(particlesPerSecond));
    }

    // Sets amount of particles to spawn next frame until emitter is 'timeSeconds' old, then spawns nothing
    void SpawnFor(uint tickCounter, float timeSeconds, int particleCount)
    {
        bool autoDelete = tickCounter * Frame.DeltaTime > timeSeconds;
        Spawn(autoDelete ? 0 : particleCount);
        SetAutoDelete(autoDelete);
    }

    // Sets amount of particles to spawn per second until emitter is 'timeSeconds' old, then spawns nothing
    void SpawnUniformFor(uint tickCounter, float timeSeconds, float particlesPerSecond)
    {
        SpawnFor(tickCounter, timeSeconds, UniformSpawn(particlesPerSecond));
    }

    // Returns true when effect has finished (considering there are no alive particles).
    bool HasFinished()
    {
        return IsStopping() || (GetSpawnCount() == 0 && GetAutoDelete());
    }
};

/////////// THIS IS ANOTHER FILE ////////////////

struct TrailEffect
{
    float3 Position;
    uint State; // Required member, 0 = running, 1 = stopping, 2 = stopped
    float3 Forward;
    float UserData;
    float3 SpawnPosition;
    float UserData2;
};

struct TrailParticle
{
    float3 StartForward;
    uint EffectIndex; // Required member
    float3 StartPosition;
    uint FrameIndex;
    float3 EndPosition;
    float UserData;

    // Get particle life in seconds
    float GetLife()
    {
        return (Frame.FrameIndex - FrameIndex) * Frame.DeltaTime;
    }

    // Gets position of billboard vertex when width would be 0 (uses billboard.VertexId to choose StartPosition or EndPosition)
    float3 GetPosition(ParticleBillboard billboard)
    {
        bool isEnd = billboard.VertexId / 2 == 0;
        return isEnd ? EndPosition : StartPosition;
    }

    void Transform(inout ParticleBillboard billboard, float width)
    {
        bool isEnd = billboard.VertexId / 2 == 0;
        float3 pos = isEnd ? EndPosition : StartPosition;
        float3 fw = isEnd ? (EndPosition - StartPosition) : StartForward;
        float3 right = normalizeSafe(cross(Frame.GetCameraPosition() - pos, fw));

        billboard.SetVertex(pos - right * width * billboard.VertexOffset.x);
    }
};

struct TrailEmitter
{
    float3 LastSpawn;
    uint State; // Required member
    float3 LastForward;
    float UserData;

    void Spawn(inout TrailParticle particle, EmitterState state, TrailEffect effect)
    {
        particle.StartPosition = state.IsFirstFrame() ? effect.SpawnPosition : LastSpawn;
        particle.StartForward = state.IsFirstFrame() ? effect.Forward : LastForward;
        particle.EndPosition = effect.Position;
        particle.FrameIndex = Frame.FrameIndex;
    }

    void Update(inout EmitterState state, TrailEffect effect)
    {
        state.Spawn(1);
        LastForward = state.IsFirstFrame() ? effect.Forward : effect.Position - LastSpawn;
        LastSpawn = effect.Position;
    }
};

//////////// THIS IS ANOTHER FILE //////////////

// Effect parameters, writable only by CPU, readable only by GPU
struct EffectParameters : TrailEffect
{
};

// Data stored per-emitter, read/write by GPU only
struct EmitterPayload : TrailEmitter
{
};

// Data stored per-particle, read/write by GPU only
struct ParticlePayload : TrailParticle
{
};

// Creates new particle
void SpawnParticle(inout ParticlePayload particle, EmitterPayload emitter,/* HERE */ EffectParameters effect, Rng rng, uint spawnIndex)
{
    emitter.Spawn(particle, state, effect);
}
tgjones commented 7 years ago

Thanks - fixed.