PVS-Studio සහ අඛණ්ඩ ඒකාබද්ධතාවය: TeamCity. Open RollerCoaster Tycoon 2 ව්‍යාපෘතියේ විශ්ලේෂණය

PVS-Studio සහ අඛණ්ඩ ඒකාබද්ධතාවය: TeamCity. Open RollerCoaster Tycoon 2 ව්‍යාපෘතියේ විශ්ලේෂණය
Один из самых актуальных сценариев использования анализатора PVS-Studio — его интеграция с CI системами. И хотя анализ проекта PVS-Studio практически из-под любой continuous integration системы можно встроить всего в несколько команд, мы продолжаем делать этот процесс ещё удобнее. В PVS-Studio появилась поддержка преобразования вывода анализатора в формат для TeamCity — TeamCity Inspections Type. Давайте посмотрим, как это работает.

භාවිතා කරන මෘදුකාංග පිළිබඳ තොරතුරු

පීවීඑස්-ස්ටුඩියෝ - C, C++, C# සහ Java කේතයේ ස්ථිතික විශ්ලේෂකයක්, විවිධ වර්ගයේ දෝෂ සෙවීම සහ නිවැරදි කිරීමේ කාර්යයට පහසුකම් සැලසීම සඳහා නිර්මාණය කර ඇත. විශ්ලේෂකය Windows, Linux සහ macOS මත භාවිතා කළ හැක. මෙම ලිපියෙන් අපි විශ්ලේෂකය පමණක් නොව, එහි බෙදාහැරීමේ සමහර උපයෝගිතා ද ක්රියාකාරීව භාවිතා කරනු ඇත.

CLMonitor — යනු සම්පාදක දියත් කිරීම් නිරීක්ෂණය කරන අධීක්ෂණ සේවාදායකයකි. ඔබේ ව්‍යාපෘතිය ගොඩනැගීමට පෙර එය වහාම ක්‍රියාත්මක කළ යුතුය. අධීක්ෂණ ප්‍රකාරයේදී, සේවාදායකය විසින් සහාය දක්වන සියලුම සම්පාදකයන්ගේ ධාවනයට බාධා කරයි. මෙම උපයෝගීතාව C/C++ ව්යාපෘති විශ්ලේෂණය කිරීමට පමණක් භාවිතා කළ හැකි බව සඳහන් කිරීම වටී.

PlogConverter - විශ්ලේෂක වාර්තා විවිධ හැඩතලවලට පරිවර්තනය කිරීම සඳහා උපයෝගීතාවයක්.

අධ්යයනය යටතේ පවතින ව්යාපෘතිය පිළිබඳ තොරතුරු

අපි මෙම ක්‍රියාකාරීත්වය ප්‍රායෝගික උදාහරණයක් මත උත්සාහ කරමු - අපි OpenRCT2 ව්‍යාපෘතිය විශ්ලේෂණය කරමු.

OpenRCT2 — открытая реализация игры RollerCoaster Tycoon 2 (RCT2), расширяющая её новыми функциями и исправляющая ошибки. Игровой процесс вращается вокруг строительства и содержания парка развлечений, в котором находятся аттракционы, магазины и объекты. Игрок должен постараться получить прибыль и поддерживать хорошую репутацию парка, сохраняя при этом гостей счастливыми. OpenRCT2 позволяет играть как в сценарии, так и в песочнице. Сценарии требуют, чтобы игрок выполнил определенную задачу в установленное время, в то время как песочница позволяет игроку построить более гибкий парк без каких-либо ограничений или финансов.

ගැලපුම්

කාලය ඉතිරි කර ගැනීම සඳහා, මම බොහෝ විට ස්ථාපන ක්‍රියාවලිය මඟ හැර මගේ පරිගණකයේ TeamCity සේවාදායකය ක්‍රියාත්මක වන මොහොතේ සිට ආරම්භ කරමි. අපට යන්න අවශ්‍ය වන්නේ: localhost:{ස්ථාපන ක්‍රියාවලියේදී දක්වා ඇති වරාය} (මගේ නඩුවේදී, localhost:9090) සහ අවසර දත්ත ඇතුළත් කරන්න. ඇතුළු වූ පසු අපව පිළිගනු ලබන්නේ:

PVS-Studio සහ අඛණ්ඩ ඒකාබද්ධතාවය: TeamCity. Open RollerCoaster Tycoon 2 ව්‍යාපෘතියේ විශ්ලේෂණය
Create Project බොත්තම ක්ලික් කරන්න. ඊළඟට, අතින් තෝරන්න සහ ක්ෂේත්ර පුරවන්න.

PVS-Studio සහ අඛණ්ඩ ඒකාබද්ධතාවය: TeamCity. Open RollerCoaster Tycoon 2 ව්‍යාපෘතියේ විශ්ලේෂණය
බොත්තම එබීමෙන් පසු නිර්මාණය, සැකසුම් සහිත කවුළුවකින් අපව පිළිගනු ලැබේ.

PVS-Studio සහ අඛණ්ඩ ඒකාබද්ධතාවය: TeamCity. Open RollerCoaster Tycoon 2 ව්‍යාපෘතියේ විශ්ලේෂණය
අපි ක්ලික් කරමු ගොඩනැගීමේ වින්‍යාසය සාදන්න.

PVS-Studio සහ අඛණ්ඩ ඒකාබද්ධතාවය: TeamCity. Open RollerCoaster Tycoon 2 ව්‍යාපෘතියේ විශ්ලේෂණය
ක්ෂේත්ර පුරවා ක්ලික් කරන්න නිර්මාණය. අනුවාද පාලන පද්ධතියක් තෝරා ගැනීමට ඔබෙන් ඉල්ලා සිටින කවුළුවක් අපට පෙනේ. මූලාශ්ර දැනටමත් දේශීයව පිහිටා ඇති බැවින්, ක්ලික් කරන්න මගහරින්න.

PVS-Studio සහ අඛණ්ඩ ඒකාබද්ධතාවය: TeamCity. Open RollerCoaster Tycoon 2 ව්‍යාපෘතියේ විශ්ලේෂණය
අවසාන වශයෙන්, අපි ව්යාපෘති සැකසුම් වෙත යන්නෙමු.

PVS-Studio සහ අඛණ්ඩ ඒකාබද්ධතාවය: TeamCity. Open RollerCoaster Tycoon 2 ව්‍යාපෘතියේ විශ්ලේෂණය
අපි එකලස් කිරීමේ පියවර එකතු කරමු, මෙය කිරීමට ක්ලික් කරන්න: ගොඩනැගීම පියවර -> ගොඩනැගීමේ පියවර එක් කරන්න.

PVS-Studio සහ අඛණ්ඩ ඒකාබද්ධතාවය: TeamCity. Open RollerCoaster Tycoon 2 ව්‍යාපෘතියේ විශ්ලේෂණය
මෙන්න අපි තෝරා ගන්නේ:

  • ධාවන වර්ගය -> විධාන රේඛාව
  • Run -> Custom Script

ව්‍යාපෘති සම්පාදනයේදී අපි විශ්ලේෂණය සිදු කරන බැවින්, එකලස් කිරීම සහ විශ්ලේෂණය එක් පියවරක් විය යුතුය, එබැවින් ක්ෂේත්‍රය පුරවන්න අභිරුචි පිටපත:

PVS-Studio සහ අඛණ්ඩ ඒකාබද්ධතාවය: TeamCity. Open RollerCoaster Tycoon 2 ව්‍යාපෘතියේ විශ්ලේෂණය
අපි පසුව තනි පියවර දෙස බලමු. විශ්ලේෂකය පැටවීම, ව්‍යාපෘතිය එකලස් කිරීම, එය විශ්ලේෂණය කිරීම, වාර්තාව ප්‍රතිදානය කිරීම සහ හැඩතල ගැන්වීම සඳහා ගත වන්නේ කේත පේළි එකොළහක් පමණක් වීම වැදගත්ය.

අප කළ යුතු අවසාන දෙය නම් පරිසර විචල්‍යයන් සැකසීමයි, ඒවායේ කියවීමේ හැකියාව වැඩිදියුණු කිරීමට මම ක්‍රම කිහිපයක් ගෙනහැර දක්වා ඇත. මෙය සිදු කිරීම සඳහා, අපි ඉදිරියට යමු: පරාමිති -> නව පරාමිතිය එක් කරන්න සහ විචල්‍ය තුනක් එකතු කරන්න:

PVS-Studio සහ අඛණ්ඩ ඒකාබද්ධතාවය: TeamCity. Open RollerCoaster Tycoon 2 ව්‍යාපෘතියේ විශ්ලේෂණය
ඔබ කළ යුත්තේ බොත්තම ඔබන්න දුවන්න ඉහළ දකුණු කෙළවරේ. ව්‍යාපෘතිය එකලස් කර විශ්ලේෂණය කරන අතරතුර, මම ඔබට පිටපත ගැන කියන්නම්.

කෙලින්ම පිටපත

පළමුව, අපි නවතම 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"

මේ අතර, ව්‍යාපෘතියේ එකලස් කිරීම සහ විශ්ලේෂණය සාර්ථකව නිම කර ඇත, අපට ටැබ් එකට යා හැකිය ව්යාපෘති සහ එය සහතික කර ගන්න.

PVS-Studio සහ අඛණ්ඩ ඒකාබද්ධතාවය: TeamCity. Open RollerCoaster Tycoon 2 ව්‍යාපෘතියේ විශ්ලේෂණය
දැන් අපි ක්ලික් කරමු පරීක්ෂණ මුළුවිශ්ලේෂක වාර්තාව නැරඹීමට යාමට:

PVS-Studio සහ අඛණ්ඩ ඒකාබද්ධතාවය: TeamCity. Open RollerCoaster Tycoon 2 ව්‍යාපෘතියේ විශ්ලේෂණය
අනතුරු ඇඟවීම් රෝග විනිශ්චය රීති අංක අනුව කාණ්ඩ කර ඇත. කේතය හරහා සැරිසැරීමට, ඔබ අනතුරු ඇඟවීම සමඟ රේඛා අංකය මත ක්ලික් කළ යුතුය. ඉහළ දකුණු කෙළවරේ ඇති ප්‍රශ්න ලකුණ මත ක්ලික් කිරීමෙන් ඔබට ලේඛන සහිත නව ටැබ් එකක් විවෘත වේ. විශ්ලේෂක අනතුරු ඇඟවීම සමඟ රේඛා අංකය මත ක්ලික් කිරීමෙන් ඔබට කේතය හරහා සැරිසැරීමටද හැකිය. භාවිතා කරන විට දුරස්ථ පරිගණකයකින් සංචාලනය කළ හැකිය SourceTreeRoot සලකුණ. විශ්ලේෂකයේ මෙම මෙහෙයුම් ආකාරය ගැන උනන්දුවක් දක්වන ඕනෑම කෙනෙකුට අදාළ කොටස සමඟ හුරුපුරුදු විය හැකිය ලියකියවිලි.

විශ්ලේෂකයේ ප්‍රතිඵල බැලීම

දැන් අපි ගොඩනැගීම යෙදවීම සහ වින්‍යාස කිරීම අවසන් කර ඇති බැවින්, අප සොයන ව්‍යාපෘතියේ ඇති රසවත් අනතුරු ඇඟවීම් කිහිපයක් දෙස බලමු.

අනතුරු ඇඟවීම N1

V773 [CWE-401] 'ප්‍රතිඵල' දර්ශකය නිකුත් නොකර ව්‍යතිරේකය විසි කරන ලදී. මතක කාන්දුවක් විය හැක. libopenrct2 ObjectFactory.cpp 443

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

V501 '|' හි වමට සහ දකුණට සමාන උප ප්‍රකාශන '(1ULL << WIDX_MONTH_BOX)' ඇත. ක්රියාකරු. libopenrct2ui Cheats.cpp 487

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

V703 ව්‍යුත්පන්න පන්තියේ 'RCT12BannerElement' හි 'කොඩි' ක්ෂේත්‍රය පාදක පන්තියේ 'RCT12TileElementBase' ක්ෂේත්‍රය උඩින් ලිවීම අමුතුයි. පිරික්සුම් රේඛා: RCT12.h:570, RCT12.h:259. libopenrct2 RCT12.h 570

struct RCT12SpriteBase
{
  ....
  uint8_t flags;
  ....
};
struct rct1_peep : RCT12SpriteBase
{
  ....
  uint8_t flags;
  ....
};

Конечно, использование переменной с одним именем в базовом классе и в наследнике далеко не всегда является ошибкой. Однако технология наследования сама по себе предполагает наличие всех полей родительского класса в дочернем. Объявив же в наследнике поля с таким же именем, мы вносим путаницу.

අනතුරු ඇඟවීම N4

V793 'imageDirection / 8' ප්‍රකාශයේ ප්‍රතිඵලය කොන්දේසියේ කොටසක් වීම අමුතුයි. සමහර විට, මෙම ප්රකාශය වෙනත් දෙයක් සමඟ සැසඳිය යුතුය. libopenrct2 ObservationTower.cpp 38

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

V587 මෙම ආකාරයේ පැවරුම්වල අමුතු අනුපිළිවෙලක්: A = B; B = A;. පිරික්සුම් රේඛා: 1115, 1118. libopenrct2ui MouseInput.cpp 1118

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

V1004 [CWE-476] 'ප්ලේයර්' පොයින්ටරය nullptr ට එරෙහිව සත්‍යාපනය කිරීමෙන් පසු අනාරක්ෂිත ලෙස භාවිතා කරන ලදී. පිරික්සුම් රේඛා: 2085, 2094. libopenrct2 Network.cpp 2094

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

V547 [CWE-570] ප්‍රකාශනය 'නම == nullptr' සැමවිටම අසත්‍ය වේ. libopenrct2 ServerList.cpp 102

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

V1048 [CWE-1164] 'ColumnHeaderPressedCurrentState' විචල්‍යයට එම අගයම පවරන ලදී. libopenrct2ui CustomListView.cpp 510

void CustomListView::MouseUp(....)
{
  ....
  if (!ColumnHeaderPressedCurrentState)
  {
    ColumnHeaderPressed = std::nullopt;
    ColumnHeaderPressedCurrentState = false;
    Invalidate();
  }
}

කේතය තරමක් අමුතු පෙනුමක්. මට පේන විදියට variable එක Re-assign කරනකොට Condition එකේ හරි නැත්නම් ටයිප් එකේ වැරදීමක් වෙලා තියෙනවා ColumnHeaderPressedCurrentState තේරුම බොරු.

නිගමනය

අපට පෙනෙන පරිදි, ඔබේ TeamCity ව්‍යාපෘතියට PVS-Studio ස්ථිතික විශ්ලේෂකය ඒකාබද්ධ කිරීම ඉතා සරල ය. මෙය සිදු කිරීම සඳහා, එක් කුඩා වින්‍යාස ගොනුවක් ලිවීම ප්‍රමාණවත් වේ. කේතය පරීක්ෂා කිරීමෙන් එකලස් කිරීමෙන් පසු වහාම ගැටළු හඳුනා ගැනීමට ඔබට ඉඩ සලසයි, වෙනස්කම් වල සංකීර්ණත්වය සහ පිරිවැය තවමත් අඩු වන විට ඒවා ඉවත් කිරීමට උපකාරී වේ.

PVS-Studio සහ අඛණ්ඩ ඒකාබද්ධතාවය: TeamCity. Open RollerCoaster Tycoon 2 ව්‍යාපෘතියේ විශ්ලේෂණය
ඔබට මෙම ලිපිය ඉංග්‍රීසි කතා කරන ප්‍රේක්ෂකයින් සමඟ බෙදා ගැනීමට අවශ්‍ය නම්, කරුණාකර පරිවර්තන සබැඳිය භාවිතා කරන්න: Vladislav Stolyarov. PVS-Studio සහ අඛණ්ඩ ඒකාබද්ධතාවය: TeamCity. Open RollerCoaster Tycoon 2 ව්‍යාපෘතියේ විශ්ලේෂණය.

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න