Один из самых актуальных сценариев использования анализатора PVS-Studio — его интеграция с CI системами. И хотя анализ проекта PVS-Studio практически из-под любой continuous integration системы можно встроить всего в несколько команд, мы продолжаем делать этот процесс ещё удобнее. В PVS-Studio появилась поддержка преобразования вывода анализатора в формат для TeamCity — TeamCity Inspections Type. Давайте посмотрим, как это работает.
භාවිතා කරන මෘදුකාංග පිළිබඳ තොරතුරු
අධ්යයනය යටතේ පවතින ව්යාපෘතිය පිළිබඳ තොරතුරු
අපි මෙම ක්රියාකාරීත්වය ප්රායෝගික උදාහරණයක් මත උත්සාහ කරමු - අපි OpenRCT2 ව්යාපෘතිය විශ්ලේෂණය කරමු.
ගැලපුම්
කාලය ඉතිරි කර ගැනීම සඳහා, මම බොහෝ විට ස්ථාපන ක්රියාවලිය මඟ හැර මගේ පරිගණකයේ TeamCity සේවාදායකය ක්රියාත්මක වන මොහොතේ සිට ආරම්භ කරමි. අපට යන්න අවශ්ය වන්නේ: localhost:{ස්ථාපන ක්රියාවලියේදී දක්වා ඇති වරාය} (මගේ නඩුවේදී, localhost:9090) සහ අවසර දත්ත ඇතුළත් කරන්න. ඇතුළු වූ පසු අපව පිළිගනු ලබන්නේ:
Create Project බොත්තම ක්ලික් කරන්න. ඊළඟට, අතින් තෝරන්න සහ ක්ෂේත්ර පුරවන්න.
බොත්තම එබීමෙන් පසු නිර්මාණය, සැකසුම් සහිත කවුළුවකින් අපව පිළිගනු ලැබේ.
අපි ක්ලික් කරමු ගොඩනැගීමේ වින්යාසය සාදන්න.
ක්ෂේත්ර පුරවා ක්ලික් කරන්න නිර්මාණය. අනුවාද පාලන පද්ධතියක් තෝරා ගැනීමට ඔබෙන් ඉල්ලා සිටින කවුළුවක් අපට පෙනේ. මූලාශ්ර දැනටමත් දේශීයව පිහිටා ඇති බැවින්, ක්ලික් කරන්න මගහරින්න.
අවසාන වශයෙන්, අපි ව්යාපෘති සැකසුම් වෙත යන්නෙමු.
අපි එකලස් කිරීමේ පියවර එකතු කරමු, මෙය කිරීමට ක්ලික් කරන්න: ගොඩනැගීම පියවර -> ගොඩනැගීමේ පියවර එක් කරන්න.
මෙන්න අපි තෝරා ගන්නේ:
- ධාවන වර්ගය -> විධාන රේඛාව
- Run -> Custom Script
ව්යාපෘති සම්පාදනයේදී අපි විශ්ලේෂණය සිදු කරන බැවින්, එකලස් කිරීම සහ විශ්ලේෂණය එක් පියවරක් විය යුතුය, එබැවින් ක්ෂේත්රය පුරවන්න අභිරුචි පිටපත:
අපි පසුව තනි පියවර දෙස බලමු. විශ්ලේෂකය පැටවීම, ව්යාපෘතිය එකලස් කිරීම, එය විශ්ලේෂණය කිරීම, වාර්තාව ප්රතිදානය කිරීම සහ හැඩතල ගැන්වීම සඳහා ගත වන්නේ කේත පේළි එකොළහක් පමණක් වීම වැදගත්ය.
අප කළ යුතු අවසාන දෙය නම් පරිසර විචල්යයන් සැකසීමයි, ඒවායේ කියවීමේ හැකියාව වැඩිදියුණු කිරීමට මම ක්රම කිහිපයක් ගෙනහැර දක්වා ඇත. මෙය සිදු කිරීම සඳහා, අපි ඉදිරියට යමු: පරාමිති -> නව පරාමිතිය එක් කරන්න සහ විචල්ය තුනක් එකතු කරන්න:
ඔබ කළ යුත්තේ බොත්තම ඔබන්න දුවන්න ඉහළ දකුණු කෙළවරේ. ව්යාපෘතිය එකලස් කර විශ්ලේෂණය කරන අතරතුර, මම ඔබට පිටපත ගැන කියන්නම්.
කෙලින්ම පිටපත
පළමුව, අපි නවතම PVS-Studio බෙදාහැරීම බාගත කළ යුතුය. මේ සඳහා අපි භාවිතා කරන්නේ Chocolatey pack manager එක. මේ ගැන වැඩි විස්තර දැන ගැනීමට කැමති අය සඳහා, අනුරූපී ඇත
choco install pvs-studio -y
Далее запустим утилиту отслеживания сборки проекта CLMonitor.
%CLmon% monitor –-attach
එවිට අපි පරිසර විචල්යයක් ලෙස ව්යාපෘතිය ගොඩනඟමු එම්.එස්.බී. මට ගොඩනගා ගැනීමට අවශ්ය MSBuild අනුවාදය සඳහා මාර්ගය වේ
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable
Введём логин и ключ лицензии PVS-Studio:
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
ගොඩනැගීම අවසන් වූ පසු, පෙර සැකසූ ගොනු සහ ස්ථිතික විශ්ලේෂණය උත්පාදනය කිරීමට CLMonitor නැවත ධාවනය කරන්න:
%CLmon% analyze -l "c:ptest.plog"
එවිට අපි අපගේ බෙදා හැරීමෙන් වෙනත් උපයෝගීතාවයක් භාවිතා කරමු. PlogConverter වාර්තාවක් සම්මත ආකෘතියකින් TeamCity-විශේෂිත ආකෘතියකට පරිවර්තනය කරයි. මෙයට ස්තූතියි, අපට එය ගොඩනැගීමේ කවුළුව තුළ කෙලින්ම බැලීමට හැකි වනු ඇත.
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"
අවසාන පියවර වන්නේ ආකෘතිගත වාර්තාව ප්රදර්ශනය කිරීමයි stdout, где его подхватит парсер TeamCity.
type "C:tempptest.plog_TeamCity.txt"
සම්පූර්ණ ස්ක්රිප්ට් කේතය:
choco install pvs-studio -y
%CLmon% monitor --attach
set platform=x64
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
%CLmon% analyze -l "c:ptest.plog"
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"
type "C:tempptest.plog_TeamCity.txt"
මේ අතර, ව්යාපෘතියේ එකලස් කිරීම සහ විශ්ලේෂණය සාර්ථකව නිම කර ඇත, අපට ටැබ් එකට යා හැකිය ව්යාපෘති සහ එය සහතික කර ගන්න.
දැන් අපි ක්ලික් කරමු පරීක්ෂණ මුළුවිශ්ලේෂක වාර්තාව නැරඹීමට යාමට:
අනතුරු ඇඟවීම් රෝග විනිශ්චය රීති අංක අනුව කාණ්ඩ කර ඇත. කේතය හරහා සැරිසැරීමට, ඔබ අනතුරු ඇඟවීම සමඟ රේඛා අංකය මත ක්ලික් කළ යුතුය. ඉහළ දකුණු කෙළවරේ ඇති ප්රශ්න ලකුණ මත ක්ලික් කිරීමෙන් ඔබට ලේඛන සහිත නව ටැබ් එකක් විවෘත වේ. විශ්ලේෂක අනතුරු ඇඟවීම සමඟ රේඛා අංකය මත ක්ලික් කිරීමෙන් ඔබට කේතය හරහා සැරිසැරීමටද හැකිය. භාවිතා කරන විට දුරස්ථ පරිගණකයකින් සංචාලනය කළ හැකිය SourceTreeRoot සලකුණ. විශ්ලේෂකයේ මෙම මෙහෙයුම් ආකාරය ගැන උනන්දුවක් දක්වන ඕනෑම කෙනෙකුට අදාළ කොටස සමඟ හුරුපුරුදු විය හැකිය
විශ්ලේෂකයේ ප්රතිඵල බැලීම
දැන් අපි ගොඩනැගීම යෙදවීම සහ වින්යාස කිරීම අවසන් කර ඇති බැවින්, අප සොයන ව්යාපෘතියේ ඇති රසවත් අනතුරු ඇඟවීම් කිහිපයක් දෙස බලමු.
අනතුරු ඇඟවීම N1
Object* CreateObjectFromJson(....)
{
Object* result = nullptr;
....
result = CreateObject(entry);
....
if (readContext.WasError())
{
throw std::runtime_error("Object has errors");
}
....
}
Object* CreateObject(const rct_object_entry& entry)
{
Object* result;
switch (entry.GetType())
{
case OBJECT_TYPE_RIDE:
result = new RideObject(entry);
break;
case OBJECT_TYPE_SMALL_SCENERY:
result = new SmallSceneryObject(entry);
break;
case OBJECT_TYPE_LARGE_SCENERY:
result = new LargeSceneryObject(entry);
break;
....
default:
throw std::runtime_error("Invalid object type");
}
return result;
}
මතකය ගතිකව වෙන් කිරීමෙන් පසු විශ්ලේෂකය දෝෂයක් දුටුවේය CreateObject, ව්යතිරේකයක් සිදු වූ විට, මතකය ඉවත් නොකෙරේ, මතක කාන්දුවක් සිදු වේ.
අනතුරු ඇඟවීම N2
static uint64_t window_cheats_page_enabled_widgets[] =
{
MAIN_CHEAT_ENABLED_WIDGETS |
(1ULL << WIDX_NO_MONEY) |
(1ULL << WIDX_ADD_SET_MONEY_GROUP) |
(1ULL << WIDX_MONEY_SPINNER) |
(1ULL << WIDX_MONEY_SPINNER_INCREMENT) |
(1ULL << WIDX_MONEY_SPINNER_DECREMENT) |
(1ULL << WIDX_ADD_MONEY) |
(1ULL << WIDX_SET_MONEY) |
(1ULL << WIDX_CLEAR_LOAN) |
(1ULL << WIDX_DATE_SET) |
(1ULL << WIDX_MONTH_BOX) | // <=
(1ULL << WIDX_MONTH_UP) |
(1ULL << WIDX_MONTH_DOWN) |
(1ULL << WIDX_YEAR_BOX) |
(1ULL << WIDX_YEAR_UP) |
(1ULL << WIDX_YEAR_DOWN) |
(1ULL << WIDX_DAY_BOX) |
(1ULL << WIDX_DAY_UP) |
(1ULL << WIDX_DAY_DOWN) |
(1ULL << WIDX_MONTH_BOX) | // <=
(1ULL << WIDX_DATE_GROUP) |
(1ULL << WIDX_DATE_RESET),
....
};
ස්ථිතික විශ්ලේෂකයෙකු හැර වෙනත් කිහිප දෙනෙකුට මෙම අවධානය යොමු කිරීමේ පරීක්ෂණය සමත් විය හැකිය. මේ කොපි පේස්ට් උදාහරණය හරියටම මේ හේතුව නිසා හොඳයි.
අනතුරු ඇඟවීම් N3
struct RCT12SpriteBase
{
....
uint8_t flags;
....
};
struct rct1_peep : RCT12SpriteBase
{
....
uint8_t flags;
....
};
Конечно, использование переменной с одним именем в базовом классе и в наследнике далеко не всегда является ошибкой. Однако технология наследования сама по себе предполагает наличие всех полей родительского класса в дочернем. Объявив же в наследнике поля с таким же именем, мы вносим путаницу.
අනතුරු ඇඟවීම N4
void vehicle_visual_observation_tower(...., int32_t imageDirection, ....)
{
if ((imageDirection / 8) && (imageDirection / 8) != 3)
{
....
}
....
}
අපි සමීපව බලමු. ප්රකාශනය imageDirection / 8 නම් අසත්ය වනු ඇත රූප දිශාව -7 සිට 7 දක්වා පරාසයක පවතී. දෙවන කොටස: (රූප දිශාව / 8) != 3 проверяет රූප දිශාව на нахождение вне диапазона: от -31 до -24 и от 24 до 31 соответственно. Мне кажется довольно странным проверять числа на вхождение в определённый диапазон таким способом и, даже если в данном фрагменте кода нет ошибки, я бы рекомендовал переписать данные условия на более явные. Это существенно упростило бы жизнь людям, которые будут читать и поддерживать этот код.
අනතුරු ඇඟවීම N5
void process_mouse_over(....)
{
....
switch (window->widgets[widgetId].type)
{
case WWT_VIEWPORT:
ebx = 0;
edi = cursorId; // <=
// Window event WE_UNKNOWN_0E was called here,
// but no windows actually implemented a handler and
// it's not known what it was for
cursorId = edi; // <=
if ((ebx & 0xFF) != 0)
{
set_cursor(cursorId);
return;
}
break;
....
}
....
}
මෙම කේත ඛණ්ඩය බොහෝ විට දිරාපත් වීමෙන් ලබාගෙන ඇත. ඉන්පසුව, ඉතිරිව ඇති අදහස අනුව විනිශ්චය කිරීම, වැඩ නොකරන කේතයේ කොටසක් ඉවත් කරන ලදී. කෙසේ වෙතත්, තවමත් මෙහෙයුම් කිහිපයක් ඉතිරිව ඇත cursorId, එය ද එතරම් තේරුමක් නැත.
අනතුරු ඇඟවීම N6
void Network::ProcessPlayerList()
{
....
auto* player = GetPlayerByID(pendingPlayer.Id);
if (player == nullptr)
{
// Add new player.
player = AddPlayer("", "");
if (player) // <=
{
*player = pendingPlayer;
if (player->Flags & NETWORK_PLAYER_FLAG_ISSERVER)
{
_serverConnection->Player = player;
}
}
newPlayers.push_back(player->Id); // <=
}
....
}
මෙම කේතය නිවැරදි කිරීම තරමක් පහසුය; ඔබ එය තුන්වන වරටත් පරීක්ෂා කළ යුතුය ක්රීඩකයා ශුන්ය දර්ශකයකට, නැතහොත් එය කොන්දේසි සහිත ප්රකාශයේ ශරීරයට එක් කරන්න. මම දෙවන විකල්පය යෝජනා කරමි:
void Network::ProcessPlayerList()
{
....
auto* player = GetPlayerByID(pendingPlayer.Id);
if (player == nullptr)
{
// Add new player.
player = AddPlayer("", "");
if (player)
{
*player = pendingPlayer;
if (player->Flags & NETWORK_PLAYER_FLAG_ISSERVER)
{
_serverConnection->Player = player;
}
newPlayers.push_back(player->Id);
}
}
....
}
අනතුරු ඇඟවීම N7
std::optional<ServerListEntry> ServerListEntry::FromJson(...)
{
auto name = json_object_get(server, "name");
.....
if (name == nullptr || version == nullptr)
{
....
}
else
{
....
entry.name = (name == nullptr ? "" : json_string_value(name));
....
}
....
}
ඔබට කියවීමට අපහසු කේත පේළියක් එක පහරකින් ඉවත් කර පරීක්ෂා කිරීමේ ගැටලුව විසඳා ගත හැක. nullptr. කේතය පහත පරිදි වෙනස් කිරීමට මම යෝජනා කරමි:
std::optional<ServerListEntry> ServerListEntry::FromJson(...)
{
auto name = json_object_get(server, "name");
.....
if (name == nullptr || version == nullptr)
{
name = ""
....
}
else
{
....
entry.name = json_string_value(name);
....
}
....
}
අනතුරු ඇඟවීම N8
void CustomListView::MouseUp(....)
{
....
if (!ColumnHeaderPressedCurrentState)
{
ColumnHeaderPressed = std::nullopt;
ColumnHeaderPressedCurrentState = false;
Invalidate();
}
}
කේතය තරමක් අමුතු පෙනුමක්. මට පේන විදියට variable එක Re-assign කරනකොට Condition එකේ හරි නැත්නම් ටයිප් එකේ වැරදීමක් වෙලා තියෙනවා ColumnHeaderPressedCurrentState තේරුම බොරු.
නිගමනය
අපට පෙනෙන පරිදි, ඔබේ TeamCity ව්යාපෘතියට PVS-Studio ස්ථිතික විශ්ලේෂකය ඒකාබද්ධ කිරීම ඉතා සරල ය. මෙය සිදු කිරීම සඳහා, එක් කුඩා වින්යාස ගොනුවක් ලිවීම ප්රමාණවත් වේ. කේතය පරීක්ෂා කිරීමෙන් එකලස් කිරීමෙන් පසු වහාම ගැටළු හඳුනා ගැනීමට ඔබට ඉඩ සලසයි, වෙනස්කම් වල සංකීර්ණත්වය සහ පිරිවැය තවමත් අඩු වන විට ඒවා ඉවත් කිරීමට උපකාරී වේ.
ඔබට මෙම ලිපිය ඉංග්රීසි කතා කරන ප්රේක්ෂකයින් සමඟ බෙදා ගැනීමට අවශ්ය නම්, කරුණාකර පරිවර්තන සබැඳිය භාවිතා කරන්න: Vladislav Stolyarov.
මූලාශ්රය: www.habr.com