diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 05d078205..1d893989e 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -5,7 +5,7 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: - check-strings: + scripted-checks: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -17,6 +17,8 @@ jobs: run: tests/scripted/verify - name: Run check-strings run: tests/scripted/check-strings + - name: Run check-namespace + run: tests/scripted/check-namespace shellcheck: runs-on: ubuntu-latest container: koalaman/shellcheck-alpine:v0.4.6 diff --git a/include/AudioPortAudio.h b/include/AudioPortAudio.h index e6750e4b4..3fd32a7ac 100644 --- a/include/AudioPortAudio.h +++ b/include/AudioPortAudio.h @@ -143,7 +143,7 @@ private: void *hostApiSpecificStreamInfo; } PaStreamParameters; -#endif +#endif // PORTAUDIO_V19 PaStream * m_paStream; PaStreamParameters m_outputParameters; diff --git a/include/AudioPulseAudio.h b/include/AudioPulseAudio.h index a4721dfbd..789296e27 100644 --- a/include/AudioPulseAudio.h +++ b/include/AudioPulseAudio.h @@ -102,6 +102,6 @@ private: } // namespace lmms -#endif +#endif // LMMS_HAVE_PULSEAUDIO #endif diff --git a/include/AudioSndio.h b/include/AudioSndio.h index b2da8eac0..606850105 100644 --- a/include/AudioSndio.h +++ b/include/AudioSndio.h @@ -87,6 +87,6 @@ private: } // namespace lmms -#endif /* LMMS_HAVE_SNDIO */ +#endif // LMMS_HAVE_SNDIO -#endif /* _AUDIO_SNDIO_H */ +#endif // _AUDIO_SNDIO_H diff --git a/include/DummyEffect.h b/include/DummyEffect.h index 675249865..9db45a3e1 100644 --- a/include/DummyEffect.h +++ b/include/DummyEffect.h @@ -50,7 +50,7 @@ public: } ; -} +} // namespace gui class DummyEffectControls : public EffectControls { diff --git a/include/DummyPlugin.h b/include/DummyPlugin.h index cf36d2159..1c763ec3e 100644 --- a/include/DummyPlugin.h +++ b/include/DummyPlugin.h @@ -66,6 +66,6 @@ protected: } ; -} // namesplace lmms +} // namespace lmms #endif diff --git a/include/IoHelper.h b/include/IoHelper.h index 4f08f5087..c7d65c917 100644 --- a/include/IoHelper.h +++ b/include/IoHelper.h @@ -22,6 +22,8 @@ * */ +#ifndef IO_HELPER_H +#define IO_HELPER_H #include "lmmsconfig.h" @@ -37,7 +39,7 @@ #ifdef LMMS_HAVE_UNISTD_H #include #endif -#endif +#endif // LMMS_BUILD_WIN32 namespace lmms { @@ -87,4 +89,6 @@ int fileToDescriptor(FILE* f, bool closeFile = true) } -} // namespace lmms \ No newline at end of file +} // namespace lmms + +#endif diff --git a/include/LmmsPalette.h b/include/LmmsPalette.h index b07aa5c84..023872254 100644 --- a/include/LmmsPalette.h +++ b/include/LmmsPalette.h @@ -23,12 +23,12 @@ * */ -#include -#include "lmms_export.h" - #ifndef LMMSPALETTE_H #define LMMSPALETTE_H +#include +#include "lmms_export.h" + namespace lmms::gui { diff --git a/include/MidiSndio.h b/include/MidiSndio.h index 35788131d..3ebd14d05 100644 --- a/include/MidiSndio.h +++ b/include/MidiSndio.h @@ -73,6 +73,6 @@ private: } // namespace lmms -#endif /* LMMS_HAVE_SNDIO */ +#endif // LMMS_HAVE_SNDIO -#endif /* _MIDI_SNDIO_H */ +#endif // _MIDI_SNDIO_H diff --git a/include/RemotePluginBase.h b/include/RemotePluginBase.h index 0a3601d7c..e309496bc 100644 --- a/include/RemotePluginBase.h +++ b/include/RemotePluginBase.h @@ -341,7 +341,7 @@ private: std::atomic_int m_lockDepth; } ; -#endif +#endif // SYNC_WITH_SHM_FIFO @@ -530,7 +530,7 @@ public: writeInt( len ); write( _s.c_str(), len ); } -#endif +#endif // SYNC_WITH_SHM_FIFO #ifndef BUILD_REMOTE_PLUGIN_CLIENT inline bool messagesLeft() @@ -562,7 +562,7 @@ public: { return waitDepthCounter() > 0; } -#endif +#endif // BUILD_REMOTE_PLUGIN_CLIENT virtual bool processMessage( const message & _m ) = 0; @@ -667,7 +667,7 @@ private: pthread_mutex_t m_receiveMutex; pthread_mutex_t m_sendMutex; -#endif +#endif // SYNC_WITH_SHM_FIFO } ; diff --git a/include/RemotePluginClient.h b/include/RemotePluginClient.h index 2d825486e..4c5fcc060 100644 --- a/include/RemotePluginClient.h +++ b/include/RemotePluginClient.h @@ -173,7 +173,7 @@ private: std::condition_variable m_cv; std::thread m_thread; }; -#endif +#endif // LMMS_BUILD_WIN32 #ifdef SYNC_WITH_SHM_FIFO RemotePluginClient::RemotePluginClient( const std::string& _shm_in, const std::string& _shm_out ) : diff --git a/include/debug.h b/include/debug.h index f619da666..f2ea29cc1 100644 --- a/include/debug.h +++ b/include/debug.h @@ -33,7 +33,7 @@ #ifndef NDEBUG #define NDEBUG #endif -#endif +#endif // LMMS_DEBUG #include #include diff --git a/include/embed.h b/include/embed.h index c8914ba47..03d767b43 100644 --- a/include/embed.h +++ b/include/embed.h @@ -65,7 +65,7 @@ inline QPixmap getIconPixmap( const QString& _name, } //QString getText( const char * _name ); -} +} // namespace PLUGIN_NAME #endif // PLUGIN_NAME diff --git a/include/lmms_math.h b/include/lmms_math.h index e1de09936..db4502f1c 100644 --- a/include/lmms_math.h +++ b/include/lmms_math.h @@ -118,7 +118,7 @@ static inline float absFraction( float _x ) } #endif -#endif +#endif // __INTEL_COMPILER @@ -153,7 +153,7 @@ static inline long double fastFmal( long double a, long double b, long double c #endif #else return a * b + c; -#endif +#endif // FP_FAST_FMAL } //! @brief Takes advantage of fmaf() function if present in hardware @@ -167,7 +167,7 @@ static inline float fastFmaf( float a, float b, float c ) #endif #else return a * b + c; -#endif +#endif // FP_FAST_FMAF } //! @brief Takes advantage of fma() function if present in hardware diff --git a/include/versioninfo.h b/include/versioninfo.h index 2bb74a570..29bf3bea9 100644 --- a/include/versioninfo.h +++ b/include/versioninfo.h @@ -1,3 +1,6 @@ +#ifndef VERSION_INFO_H +#define VERSION_INFO_H + #include "lmms_basics.h" #ifdef __GNUC__ @@ -47,3 +50,5 @@ constexpr const char* LMMS_BUILDCONF_PLATFORM = "win32"; #ifdef LMMS_BUILD_HAIKU constexpr const char* LMMS_BUILDCONF_PLATFORM = "Haiku"; #endif + +#endif diff --git a/plugins/Lv2Effect/Lv2Effect.h b/plugins/Lv2Effect/Lv2Effect.h index 7e1457777..521a7df74 100644 --- a/plugins/Lv2Effect/Lv2Effect.h +++ b/plugins/Lv2Effect/Lv2Effect.h @@ -58,4 +58,4 @@ private: } // namespace lmms -#endif // LMMS_HAVE_LV2 +#endif diff --git a/plugins/VstBase/RemoteVstPlugin.cpp b/plugins/VstBase/RemoteVstPlugin.cpp index aaf8aec3d..2b035eca7 100644 --- a/plugins/VstBase/RemoteVstPlugin.cpp +++ b/plugins/VstBase/RemoteVstPlugin.cpp @@ -57,7 +57,7 @@ #include #endif -#endif +#endif // LMMS_BUILD_LINUX #ifndef NATIVE_LINUX_VST #define USE_WS_PREFIX @@ -883,7 +883,7 @@ void RemoteVstPlugin::initEditor() pluginDispatch(effEditTop); m_x11WindowVisible = true; -#endif +#endif // NATIVE_LINUX_VST } @@ -1090,16 +1090,16 @@ void RemoteVstPlugin::process( const sampleFrame * _in, sampleFrame * _out ) #ifdef OLD_VST_SDK if( m_plugin->flags & effFlagsCanReplacing ) { -#endif m_plugin->processReplacing( m_plugin, m_inputs, m_outputs, bufferSize() ); -#ifdef OLD_VST_SDK } else { m_plugin->process( m_plugin, m_inputs, m_outputs, bufferSize() ); } +#else + m_plugin->processReplacing(m_plugin, m_inputs, m_outputs, bufferSize()); #endif unlockShm(); @@ -1937,7 +1937,7 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode, // TODO // close window, platform specific handle in return 0; -#endif +#endif // OLD_VST_SDK case audioMasterSizeWindow: { @@ -2334,7 +2334,7 @@ void RemoteVstPlugin::guiEventLoop() } } } -#endif +#endif // NATIVE_LINUX_VST #ifndef NATIVE_LINUX_VST @@ -2385,7 +2385,7 @@ LRESULT CALLBACK RemoteVstPlugin::wndProc( HWND hwnd, UINT uMsg, } -#endif +#endif // NATIVE_LINUX_VST } // namespace lmms @@ -2421,7 +2421,7 @@ int main( int _argc, char * * _argv ) sched_get_priority_min( SCHED_FIFO ) ) / 2; sched_setscheduler( 0, SCHED_FIFO, &sparam ); #endif -#endif +#endif // LMMS_BUILD_LINUX #ifdef LMMS_BUILD_WIN32 if( !SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ) ) diff --git a/plugins/VstBase/VstPlugin.cpp b/plugins/VstBase/VstPlugin.cpp index bba644305..46d2057dd 100644 --- a/plugins/VstBase/VstPlugin.cpp +++ b/plugins/VstBase/VstPlugin.cpp @@ -111,7 +111,7 @@ private: uchar* m_map; }; -} +} // namespace PE namespace lmms { diff --git a/plugins/Xpressive/ExprSynth.cpp b/plugins/Xpressive/ExprSynth.cpp index e7d7e0951..0a1454345 100644 --- a/plugins/Xpressive/ExprSynth.cpp +++ b/plugins/Xpressive/ExprSynth.cpp @@ -363,7 +363,7 @@ namespace SimpleRandom { return dist(generator); } }; -} +} // namespace SimpleRandom static freefunc0 simple_rand; diff --git a/plugins/ZynAddSubFx/LocalZynAddSubFx.cpp b/plugins/ZynAddSubFx/LocalZynAddSubFx.cpp index 2b0c0d974..36f7ce48c 100644 --- a/plugins/ZynAddSubFx/LocalZynAddSubFx.cpp +++ b/plugins/ZynAddSubFx/LocalZynAddSubFx.cpp @@ -64,7 +64,7 @@ LocalZynAddSubFx::LocalZynAddSubFx() : pthread_win32_process_attach_np(); pthread_win32_thread_attach_np(); #endif -#endif +#endif // LMMS_BUILD_WIN32 initConfig(); diff --git a/plugins/ZynAddSubFx/RemoteZynAddSubFx.cpp b/plugins/ZynAddSubFx/RemoteZynAddSubFx.cpp index b2e47cade..1de5fb97d 100644 --- a/plugins/ZynAddSubFx/RemoteZynAddSubFx.cpp +++ b/plugins/ZynAddSubFx/RemoteZynAddSubFx.cpp @@ -278,7 +278,7 @@ int main( int _argc, char * * _argv ) pthread_win32_process_attach_np(); pthread_win32_thread_attach_np(); #endif -#endif +#endif // LMMS_BUILD_WIN32 #ifdef SYNC_WITH_SHM_FIFO @@ -298,7 +298,7 @@ int main( int _argc, char * * _argv ) pthread_win32_thread_detach_np(); pthread_win32_process_detach_np(); #endif -#endif +#endif // LMMS_BUILD_WIN32 return 0; } diff --git a/src/core/ConfigManager.cpp b/src/core/ConfigManager.cpp index 59987de97..dbad06784 100644 --- a/src/core/ConfigManager.cpp +++ b/src/core/ConfigManager.cpp @@ -566,7 +566,7 @@ void ConfigManager::loadConfigFile(const QString & configFile) } #endif } -#endif +#endif // LMMS_HAVE_STK upgrade(); diff --git a/src/core/DrumSynth.cpp b/src/core/DrumSynth.cpp index 79630e42d..bc5455c96 100644 --- a/src/core/DrumSynth.cpp +++ b/src/core/DrumSynth.cpp @@ -37,7 +37,7 @@ #ifdef _MSC_VER //not #if LMMS_BUILD_WIN32 because we have strncasecmp in mingw #define strcasecmp _stricmp -#endif +#endif // _MSC_VER namespace lmms { diff --git a/src/core/SampleBuffer.cpp b/src/core/SampleBuffer.cpp index b931b27b5..68d9af2c9 100644 --- a/src/core/SampleBuffer.cpp +++ b/src/core/SampleBuffer.cpp @@ -672,7 +672,7 @@ f_cnt_t SampleBuffer::decodeSampleOGGVorbis( return frames; } -#endif +#endif // LMMS_HAVE_OGGVORBIS @@ -1258,7 +1258,7 @@ void flacStreamEncoderMetadataCallback( b->write((const char *) metadata, sizeof(*metadata)); } -#endif +#endif // LMMS_HAVE_FLAC_STREAM_ENCODER_H @@ -1314,12 +1314,12 @@ QString & SampleBuffer::toBase64(QString & dst) const base64::encode(baWriter.buffer().data(), baWriter.buffer().size(), dst); -#else /* LMMS_HAVE_FLAC_STREAM_ENCODER_H */ +#else // LMMS_HAVE_FLAC_STREAM_ENCODER_H base64::encode((const char *) m_data, m_frames * sizeof(sampleFrame), dst); -#endif /* LMMS_HAVE_FLAC_STREAM_ENCODER_H */ +#endif // LMMS_HAVE_FLAC_STREAM_ENCODER_H return dst; } @@ -1461,7 +1461,7 @@ void flacStreamDecoderErrorCallback( // what to do now?? } -#endif +#endif // LMMS_HAVE_FLAC_STREAM_DECODER_H void SampleBuffer::loadFromBase64(const QString & data) @@ -1517,7 +1517,7 @@ void SampleBuffer::loadFromBase64(const QString & data) m_origData = MM_ALLOC( m_origFrames); memcpy(m_origData, dst, dsize); -#endif +#endif // LMMS_HAVE_FLAC_STREAM_DECODER_H delete[] dst; diff --git a/src/core/audio/AudioAlsa.cpp b/src/core/audio/AudioAlsa.cpp index 0cf95f895..1a22413d8 100644 --- a/src/core/audio/AudioAlsa.cpp +++ b/src/core/audio/AudioAlsa.cpp @@ -542,4 +542,4 @@ int AudioAlsa::setSWParams() } // namespace lmms -#endif +#endif // LMMS_HAVE_ALSA diff --git a/src/core/audio/AudioFileMP3.cpp b/src/core/audio/AudioFileMP3.cpp index 75084460f..4930e9ad6 100644 --- a/src/core/audio/AudioFileMP3.cpp +++ b/src/core/audio/AudioFileMP3.cpp @@ -134,4 +134,4 @@ void AudioFileMP3::tearDownEncoder() } // namespace lmms -#endif +#endif // LMMS_HAVE_MP3LAME diff --git a/src/core/audio/AudioFileOgg.cpp b/src/core/audio/AudioFileOgg.cpp index 1f40f456e..d61e27da8 100644 --- a/src/core/audio/AudioFileOgg.cpp +++ b/src/core/audio/AudioFileOgg.cpp @@ -272,6 +272,6 @@ void AudioFileOgg::finishEncoding() } // namespace lmms -#endif +#endif // LMMS_HAVE_OGGVORBIS diff --git a/src/core/audio/AudioJack.cpp b/src/core/audio/AudioJack.cpp index 071a6e3c3..daf5bbd10 100644 --- a/src/core/audio/AudioJack.cpp +++ b/src/core/audio/AudioJack.cpp @@ -339,7 +339,7 @@ void AudioJack::renamePort( AudioPort * _port ) #endif } } -#endif +#endif // AUDIO_PORT_SUPPORT } @@ -502,4 +502,4 @@ void AudioJack::setupWidget::saveSettings() } // namespace lmms -#endif +#endif // LMMS_HAVE_JACK diff --git a/src/core/audio/AudioOss.cpp b/src/core/audio/AudioOss.cpp index 4480e399c..d79ed939d 100644 --- a/src/core/audio/AudioOss.cpp +++ b/src/core/audio/AudioOss.cpp @@ -362,5 +362,5 @@ void AudioOss::setupWidget::saveSettings() } // namespace lmms -#endif +#endif // LMMS_HAVE_OSS diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index b1e9cb5c4..03bceaa89 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -511,7 +511,7 @@ void AudioPortAudio::setupWidget::show() } // namespace lmms -#endif +#endif // LMMS_HAVE_PORTAUDIO diff --git a/src/core/audio/AudioPulseAudio.cpp b/src/core/audio/AudioPulseAudio.cpp index 40c955434..d1476f836 100644 --- a/src/core/audio/AudioPulseAudio.cpp +++ b/src/core/audio/AudioPulseAudio.cpp @@ -353,5 +353,5 @@ void AudioPulseAudio::setupWidget::saveSettings() } // namespace lmms -#endif +#endif // LMMS_HAVE_PULSEAUDIO diff --git a/src/core/audio/AudioSdl.cpp b/src/core/audio/AudioSdl.cpp index d321e8566..8d4687518 100644 --- a/src/core/audio/AudioSdl.cpp +++ b/src/core/audio/AudioSdl.cpp @@ -304,7 +304,7 @@ void AudioSdl::sdlAudioCallback( Uint8 * _buf, int _len ) m_convertedBufPos += min_len; m_convertedBufPos %= m_convertedBufSize; } -#endif +#endif // LMMS_HAVE_SDL2 } #ifdef LMMS_HAVE_SDL2 @@ -349,5 +349,5 @@ void AudioSdl::setupWidget::saveSettings() } // namespace lmms -#endif +#endif // LMMS_HAVE_SDL diff --git a/src/core/audio/AudioSndio.cpp b/src/core/audio/AudioSndio.cpp index 0ba801585..a8ea34ce1 100644 --- a/src/core/audio/AudioSndio.cpp +++ b/src/core/audio/AudioSndio.cpp @@ -215,4 +215,4 @@ void AudioSndio::setupWidget::saveSettings() } // namespace lmms -#endif /* LMMS_HAVE_SNDIO */ +#endif // LMMS_HAVE_SNDIO diff --git a/src/core/audio/AudioSoundIo.cpp b/src/core/audio/AudioSoundIo.cpp index 4d8c48708..633808204 100644 --- a/src/core/audio/AudioSoundIo.cpp +++ b/src/core/audio/AudioSoundIo.cpp @@ -521,4 +521,4 @@ void AudioSoundIo::setupWidget::saveSettings() } // namespace lmms -#endif +#endif // LMMS_HAVE_SOUNDIO diff --git a/src/core/main.cpp b/src/core/main.cpp index 43e744e5b..58758c2b1 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -120,7 +120,7 @@ void consoleMessageHandler(QtMsgType type, QByteArray localMsg = msg.toLocal8Bit(); fprintf(stderr, "%s\n", localMsg.constData()); } -#endif +#endif // LMMS_BUILD_WIN32 inline void loadTranslation( const QString & tname, @@ -776,7 +776,7 @@ int main( int argc, char * * argv ) printf( "Notice: could not set realtime priority.\n" ); } #endif -#endif +#endif // LMMS_HAVE_SCHED_H #endif #ifdef LMMS_BUILD_WIN32 diff --git a/src/core/midi/MidiSndio.cpp b/src/core/midi/MidiSndio.cpp index e7f2362f6..e644113b2 100644 --- a/src/core/midi/MidiSndio.cpp +++ b/src/core/midi/MidiSndio.cpp @@ -118,4 +118,4 @@ void MidiSndio::run() } // namespace lmms -#endif /* LMMS_HAVE_SNDIO */ +#endif // LMMS_HAVE_SNDIO diff --git a/src/gui/AudioAlsaSetupWidget.cpp b/src/gui/AudioAlsaSetupWidget.cpp index f6e91f8e3..8a253c75a 100644 --- a/src/gui/AudioAlsaSetupWidget.cpp +++ b/src/gui/AudioAlsaSetupWidget.cpp @@ -120,4 +120,4 @@ void AudioAlsaSetupWidget::onCurrentIndexChanged(int index) } // namespace lmms::gui -#endif +#endif // LMMS_HAVE_ALSA diff --git a/src/gui/MainApplication.cpp b/src/gui/MainApplication.cpp index a08df0f09..af8a71684 100644 --- a/src/gui/MainApplication.cpp +++ b/src/gui/MainApplication.cpp @@ -105,7 +105,7 @@ bool MainApplication::nativeEventFilter(const QByteArray& eventType, } return false; } -#endif +#endif // LMMS_BUILD_WIN32 } // namespace lmms::gui diff --git a/src/gui/MixerView.cpp b/src/gui/MixerView.cpp index 32355edd6..9103a5584 100644 --- a/src/gui/MixerView.cpp +++ b/src/gui/MixerView.cpp @@ -624,4 +624,4 @@ void MixerView::updateFaders() } -} // namesapce lmms::gui +} // namespace lmms::gui diff --git a/src/gui/instrument/PianoView.cpp b/src/gui/instrument/PianoView.cpp index b6dec8b4f..87a356afc 100644 --- a/src/gui/instrument/PianoView.cpp +++ b/src/gui/instrument/PianoView.cpp @@ -211,7 +211,7 @@ int PianoView::getKeyFromKeyEvent( QKeyEvent * _ke ) case 13: return 30; // = case 27: return 31; // ] } -#endif +#endif // LMMS_BUILD_WIN32 #if defined(LMMS_BUILD_LINUX) || defined(LMMS_BUILD_OPENBSD) || defined(LMMS_BUILD_FREEBSD) switch( k ) { @@ -292,7 +292,7 @@ int PianoView::getKeyFromKeyEvent( QKeyEvent * _ke ) case 29: return 27; // 0 = d'# case 35: return 28; // P = e' } -#endif +#endif // LMMS_BUILD_APPLE return -100; } diff --git a/tests/scripted/check-namespace b/tests/scripted/check-namespace new file mode 100755 index 000000000..8c1b405ad --- /dev/null +++ b/tests/scripted/check-namespace @@ -0,0 +1,195 @@ +#!/usr/bin/python3 + +# This script checks the code for namespace related issues +# Note: This script is not perfect. It can not parse all LMMS files, +# and does not contain a complete C++ parser. If you encounter +# difficulties with this tests, it could be a fault of your +# changes, but it could also be a fault of this script. + +import re +import subprocess +import sys +from pathlib import Path +from typing import NamedTuple + + +# types + +class BlockType: + pass + + +IF_MACRO = BlockType() +HEADER_GUARD = BlockType() +CODE_BLOCK = BlockType() +EXTERN = BlockType() + + +class Expectation(NamedTuple): + type: BlockType + statement: str # expected end statement + name: str # expected name in comment + + +# global variables + +errors = 0 + + +# functions + +def caption(my_str): + print(f'\n# {my_str}\n') + + +def error(where, match, my_str): + global errors + errors += 1 + if match: + line = match.string[:match.start()].count('\n') + 1 # first line is 1 + where = f'{where}:{line}' + print(f'Error: {where}: {my_str}') + + +if not Path('.gitmodules').is_file(): + print('You need to call this script from the LMMS top directory') + exit(1) + +result = subprocess.run(['git', 'ls-files', '*.[ch]', '*.[ch]pp', ':!tests/*'], + capture_output=True, text=True, check=True) + +known_no_namespace_lmms = { + # main.cpp + 'src/core/main.cpp', + # nothing to set under a namespace + 'include/debug.h', + 'include/versioninfo.h', + 'plugins/CarlaBase/CarlaConfig/config.h', + 'plugins/CarlaBase/DummyCarla.cpp', + # unclear why it has no namespace + 'plugins/ZynAddSubFx/RemoteZynAddSubFx.cpp', +} + +exclude_files = re.compile( + # not ours: + 'include/(aeffectx|fenv|ladspa).h|' + 'plugins/LadspaEffect/(calf|caps|cmt|swh|tap)/|' + 'plugins/MidiExport/MidiFile.hpp|' + 'plugins/ReverbSC/[a-z]|' + 'plugins/Sf2Player/fluidsynthshims.h|' + '/portsmf/' +) + +files = [Path(f) for f in result.stdout.splitlines() if not exclude_files.search(f)] + +# Debug argument +if len(sys.argv) > 1: + files = [Path(arg) for arg in sys.argv[1:]] + +statement_pattern = re.compile( + # Capture comments first to prevent them from matching any other regex + # Include next line if line ends with backslash + r'/[*](.|\n)*?[*]/|//(.*\\\n)*.*|' + + # Macro with <30 lines and no other #if inside needs no end comment + # Match here to prevent from matching next regex + # With a (?!negative lookahead) we can allow all # except the ones followed by "if" + r'^ *# *(?Pifn?def)(?=(([^#\n]|#(?!if|endif))*\n){,30} *# *endif)|' + # Macro followed by name or comment + # With (?P...) you can do a backreference to \name later + r'^ *# *(?Pifn?def|endif)(( *// *| +)(?P\w+))?|' + # Other macros where we don't want the argument + r'^ *# *(?Pinclude|if|el(se|if))|' + + # Namespace that contains no other braces needs no end comment + # With a (?=lookahead) we can let the "namespace" part be eaten by the parser + # but save the braces and their content for later so they can be matched again + r'^ *namespace *[\w:]*\s*(?={[^{}]*})|' + # Start of named namespace, extern "C" or just a opening brace + r'(^ *(namespace +(?P[\w:]+)|(?Pextern *"C"))\s*)?(?P{)|' + # End of namespace including comment, or just a closing brace + r'(?P})( *// *namespace +(?P[\w:]+))?' + + # In all the regexes above match both tab and space when a space is used + r''.replace(' ', r'[\t ]'), + # Make ^ match on every line, not just beginning of file + re.MULTILINE) + +# Comments and whitespace followed by header guard +header_guard_pattern = re.compile(r'^(/[*](.|\n)*?[*]/|//.*|\s)*#\s*(ifndef|pragma\s+once)') + +# Namespace lmms +namespace_pattern = re.compile(r'^\s*namespace\s+lmms', re.MULTILINE) + +# +# the real code +# + +caption('namespace checks') + +for cur_file in files: + if cur_file.is_file(): + cur_text = cur_file.read_text(errors='replace') + + if str(cur_file) not in known_no_namespace_lmms: + namespace_pattern.search(cur_text) or error(cur_file, None, f'File has no namespace lmms') + + header_guard = str(cur_file).endswith('.h') + expectations = [] # type: list[Expectation] + + if header_guard: + if not header_guard_pattern.match(cur_text): + error(cur_file, None, 'First statement should be header guard') + header_guard = False + + for m in statement_pattern.finditer(cur_text): + # Find the matched regex group + statement = m.group('opening_brace') or m.group('closing_brace') + if not statement: + statement = '#' + (m.group('macro') or m.group('named_macro') or m.group('short_macro') or '') + if not statement: + continue + + # Start statements + if statement == '{': + etype = EXTERN if m.group('extern') else CODE_BLOCK + expectations.append(Expectation(etype, '}', m.group('namespace'))) + elif statement.startswith('#if'): + etype = HEADER_GUARD if header_guard else IF_MACRO + expectations.append(Expectation(etype, '#endif', m.group('macro_name'))) + header_guard = False + + # End statements + elif statement == '#endif' or statement.startswith('#el') or statement == '}': + if not expectations: + error(cur_file, m, f'Unexpected {statement}') + break + # Don't pop the expectation for an #else tag, we are still waiting for the #endif + if statement.startswith('#el') and expectations[-1].statement == '#endif': + continue + exp = expectations.pop() + name = m.group('macro_name') or m.group('namespace_end') or '' + if statement != exp.statement: + error(cur_file, m, f'Expected {exp.statement} before {statement}') + break + # Require no end comment for header guard + elif exp.type is HEADER_GUARD and not name: + continue + elif exp.name and name != exp.name: + comment = 'namespace ' if exp.type is CODE_BLOCK else '' + error(cur_file, m, f'Missing comment // {comment}{exp.name}') + + # Extra checks + elif statement == '#include': + if any(True for e in expectations if e.type is CODE_BLOCK): + error(cur_file, m, '#include inside a code block') + + else: + # Leftover expected statements + for exp in reversed(expectations): + error(cur_file, None, f'Expected {exp.statement} before end of file') + +caption('summary') + +print(f'{str(errors)} errors.') +exit(1 if errors > 0 else 0) diff --git a/tests/scripted/verify b/tests/scripted/verify index 5c27ef898..20a26a303 100755 --- a/tests/scripted/verify +++ b/tests/scripted/verify @@ -81,6 +81,7 @@ lmms_main_path = Path(__file__).resolve().parent.parent.parent with tempfile.TemporaryDirectory() as tmpdir: os.chdir(tmpdir) check_strings = lmms_main_path / 'tests' / 'scripted' / 'check-strings' + check_namespace = lmms_main_path / 'tests' / 'scripted' / 'check-namespace' # create dummy carla repo Path('carla').mkdir() @@ -158,5 +159,92 @@ with tempfile.TemporaryDirectory() as tmpdir: test.expect('Error: debian/copyright: Glob/Path does not exist: NonExistent') test.expect('1 errors') + with ScriptTest(check_namespace) as test: + # minimal working example + test.run(0) # exitcode 0 - no errors expected + test.expect('0 errors') + + create_file('01_OddBraceWithinMacro.cpp', ''' + #if HAS_EVEN_BRACES + namespace lmms {} + #endif + namespace lmms { + #if HAS_ODD_BRACE + } + #endif + ''') + create_file('02_IncludeInCodeBlock.cpp', ''' + #include + extern "C" { + #include "alright.c" + } + namespace lmms { + #include + } + ''') + create_file('03_MacroComments.h', ''' + #ifndef HEADER_GUARD_NEEDS_NO_COMMENT + #define HEADER_GUARD_NEEDS_NO_COMMENT + #ifdef HAS_NESTED_NEEDS_COMMENT + #ifdef SHORT_NO_NESTED_NEEDS_NO_COMMENT + namespace lmms {} + #endif + #endif + #ifdef HAS_COMMENT + #ifdef SHORT_NO_NESTED_NEEDS_NO_COMMENT + #else + #endif + #endif // HAS_COMMENT + #endif + ''') + create_file('04_NamespaceComments.cpp', ''' + namespace lmms { + namespace ShortNamespace { + class WithDeclarationsOnly; + } + namespace LongNamespace { + class WithDefinition { + int x; + }; + } + } // namespace lmms + ''') + create_file('05_NoHeaderGuard.h', ''' + #include + namespace lmms {} + ''') + create_file('06_PragmaButNoLmms.h', ''' + // should not cause header guard warning + #pragma once + namespace not_lmms {} + ''') + create_file('07_MismatchingEndifName.h', ''' + #ifndef ABC_H + namespace lmms { + \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n + } + #endif // XYZ_H + ''') + create_file('08_MismatchingNamespaceEndName.h', ''' + #ifndef ABC_H + namespace lmms { + {} + } // namespace smml + #endif // ABC_H + ''') + test.run() + test.expect('8 errors') + test.expect(''' +Error: 01_OddBraceWithinMacro.cpp:7: Expected #endif before } +Error: 02_IncludeInCodeBlock.cpp:7: #include inside a code block +Error: 03_MacroComments.h:8: Missing comment // HAS_NESTED_NEEDS_COMMENT +Error: 04_NamespaceComments.cpp:10: Missing comment // namespace LongNamespace +Error: 05_NoHeaderGuard.h: First statement should be header guard +Error: 06_PragmaButNoLmms.h: File has no namespace lmms +Error: 07_MismatchingEndifName.h:36: Missing comment // ABC_H +Error: 08_MismatchingNamespaceEndName.h:5: Missing comment // namespace lmms +''') + + # if we made it until here without an exception, all tests have been passed print("SUCCESS")