bool RewriterASTConsumer::VisitFunctionDecl(clang::FunctionDecl const * const F)
{
    Func = F;

    if (F->isMain()) {
        TheGpuRewriter.RemoveText(F->getSourceRange());
        return true;
    }

    HasRestrictAttribute Result{F};
    if (!Result.IsRestrict()) return true;
    if (!Result.IsValid()) {
        SourceManager& TheSourceMgr = F->getASTContext().getSourceManager();
        llvm::errs() << "Not Valid amp attribute: " << Result.getLocation().printToString(TheSourceMgr) << "\n";
        return true;
    }

    if (Result.HasCPU() && !Result.HasGPU()) {
        RemoveFunction(TheGpuRewriter, F);
    }

    if (!Result.HasCPU() && Result.HasGPU()) {
        RemoveFunction(TheCpuRewriter, F);
    }

    return true;
}
void CServerRPCHandler::Unregister()
{
	CLogFile::Printf("Unregistering server RPCs");
	RemoveFunction(RPC_INITIAL_DATA);
	RemoveFunction(RPC_CHAT_INPUT);
	RemoveFunction(RPC_VEHICLE_ENTER_EXIT);
	RemoveFunction(RPC_PLAYER_SYNC);
	CLogFile::Printf("Server RPCs unregistered");
}
bool RewriterASTConsumer::VisitCallExpr(clang::CallExpr const * const Statement)
{
    if (clang::FunctionDecl const * const F = Statement->getDirectCallee()) {
        if ("compute::parallel_for_each" != F->getQualifiedNameAsString())
            return true;
        //RemoveStatement(TheGpuRewriter, Statement);
        RemoveFunction(TheGpuRewriter, Func);
        OnParallelForEachCall(Statement);
    }
    return true;
}
void CASScheduler::RemoveTimer( CScheduledFunction* pFunction )
{
	if( !pFunction )
		return;

	CScheduledFunction* pNext = m_pFunctionListHead;
	CScheduledFunction* pLast = nullptr;

	auto& engine = *m_OwningModule.GetModule()->GetEngine();

	bool bRemoved = false;

	while( pNext )
	{
		if( pNext == pFunction )
		{
			//If we're currently executing this function, remove it later.
			if( m_pCurrentFunction == pNext )
				m_bShouldRemove = true;
			else
				RemoveFunction( engine, pLast, pNext );

			bRemoved = true;
			break;
		}

		pLast = pNext;
		pNext = pNext->GetNext();
	}

	if( !bRemoved )
	{
		//Not found in the list, release reference given by Angelscript.
		pFunction->Release();
	}
}
void CASScheduler::Think( const float flCurrentTime )
{
	m_bThinking = true;

	CScheduledFunction* pNext = m_pFunctionListHead;
	CScheduledFunction* pLast = nullptr;
	CScheduledFunction* pNextNext = nullptr;

	bool bRemove;

	auto& engine = *m_OwningModule.GetModule()->GetEngine();

	{
		CASOwningContext context( engine );

		while( pNext )
		{
			bRemove = false;

			pNextNext = pNext->GetNext();

			m_pCurrentFunction = pNext;

			//Scripts can change the repeat count setting, so make sure to check it
			if( pNext->ShouldRemove() )
			{
				bRemove = true;
			}
			else
			{
				if( pNext->GetNextCallTime() <= flCurrentTime )
				{
					auto* pFunction = pNext->GetFunction();

					//Must happen before the actual call so scripts can "amend" the repeat count if they want to
					pNext->Called();

					//Set this now so scripts can modify it if they want to
					pNext->SetNextCallTime( flCurrentTime + pNext->GetRepeatTime() );

					bool bSuccess = false;

					if( auto pThis = pNext->GetThis() )
					{
						CASMethod method( *pFunction, context, pThis );

						bSuccess = method.CallArgs( CallFlag::NONE, *pNext->GetArguments() );
					}
					else
					{
						CASFunction function( *pFunction, context );

						bSuccess = function.CallArgs( CallFlag::NONE, *pNext->GetArguments() );
					}

					if( !bSuccess )
					{
						const auto szFunctionName = as::FormatFunctionName( *pFunction );
						as::log->critical( "Error: CScheduler::Think: execution of function {} failed!\n", 
										   szFunctionName );
					}

					//Could've been flagged for removal during the call.
					if( m_bShouldRemove || pNext->ShouldRemove() )
					{
						m_bShouldRemove = false;
						bRemove = true;
					}
				}
			}

			if( bRemove )
				RemoveFunction( engine, pLast, pNext );
			else
				pLast = pNext;

			pNext = pNextNext;
		}
	}

	m_flLastTime = flCurrentTime;

	m_pCurrentFunction = nullptr;

	m_bThinking = false;

	//Functions were scheduled while we were thinking, merge into the main list.
	if( m_pThinkListHead )
	{
		//pLast points to the last function in the main list; if any
		if( pLast )
			pLast->SetNext( m_pThinkListHead );
		else
			m_pFunctionListHead = m_pThinkListHead;

		m_pThinkListHead = nullptr;
	}
}
void CServerRPCHandler::Unregister()
{
	RemoveFunction(RPC_PlayerConnect);
	RemoveFunction(RPC_PlayerJoinComplete);
	RemoveFunction(RPC_Chat);
	RemoveFunction(RPC_Command);
	RemoveFunction(RPC_PlayerSpawn);
	RemoveFunction(RPC_Death);
	RemoveFunction(RPC_OnFootSync);
	RemoveFunction(RPC_InVehicleSync);
	RemoveFunction(RPC_PassengerSync);
	RemoveFunction(RPC_SmallSync);
	RemoveFunction(RPC_VehicleEnterExit);
	RemoveFunction(RPC_HeadMovement);
	RemoveFunction(RPC_EmptyVehicleSync);
	RemoveFunction(RPC_NameChange);
	RemoveFunction(RPC_CheckpointEntered);
	RemoveFunction(RPC_CheckpointLeft);
	RemoveFunction(RPC_ScriptingEventCall);
	RemoveFunction(RPC_ScriptingVehicleDeath);
	RemoveFunction(RPC_SyncActor);
	RemoveFunction(RPC_RequestActorUpdate);
}
void CServerPacketHandler::Unregister()
{
	RemoveFunction(PACKET_NEW_CONNECTION);
	RemoveFunction(PACKET_DISCONNECTED);
	RemoveFunction(PACKET_LOST_CONNECTION);
}