Skip to content

Coding Conventions

Fabian Schiebel edited this page Dec 19, 2022 · 12 revisions

Coding Guidelines

PhASAR mostly adheres to the LLVM coding guidelines that can be found here:

In addition, we have the following rules:

Pre-Commit Hook

We kindly ask you to make use of our code formatting and transformation pre-commit hook before you check-in your code to PhASAR.

To ensure that our pre-commit hook is automatically run before a commit is created, please install the hook by running the following commands in PhASAR's root directory:

$ pip install pre-commit
$ pre-commit install

Use the following script to run some very useful clang-tidy checks (and automated fixes) on the entire code base. This script runs a lot of clang-tidy checks and may be potentially expensive. You may wish to run it only once in a while, but definitely before you check-in any code.

$ cd PHASAR_ROOT
$ utils/run-phasar-checks.sh

Branches

The PhASAR repository consists of different kinds of branches.

  • master: Here we push our releases. Code inside the master-branch is required to be complete and stable.
  • development: Tracks our latest improvements on PhASAR. This branch may not directly be pushed to. Instead we rely on peer-reviewed pull-requests. Code inside development is expected to be stable, but does not have to be complete.
  • feature branches: Our feature branches have a descriptive name in CamelCase prefixed by f-. Here, our main development happens. There are no requirements on the code-quality inside of feature branches. Feature branches are branched from development and eventually merged back to development. After merging a feature branch back to development, it gets deleted.

We do not use force-push!

Abstractions

In general, we want PhASAR to be easy to use and high-performant at the same time. However, these requirements are oftentimes contradictory. For the APIs that external users of PhASAR see and use (including the APIs to implement custom dataflow analyses) we prefer usability and readability over performance. Inside the internals of PhASAR, we permit "more ugly" code that is high-performant as long as it is well documented, well abstracted and benchmarked.

#include Order

We group the #included headers into four groups which are placed in the following order:

  1. PhASAR's own headers
  2. LLVM's headers
  3. Other non-STL and non-LibC headers
  4. STL- and LibC headers

All except the STL- and LibC headers are included in Quoting Style; the STL and LibC headers are included in augular brackets.

#include vs Forward Declaration

We prefer #include over forward declarations for all non-PhASAR headers. For PhASAR's own headers we prefer forward declarations to improve incremental builds. However, for various templates that PhASAR consists of, forward declarations are oftentimes not usable, so in such cases we use #include and aim for using the C++17 extern template feature to lower compilation times.

Type Aliases

PhASAR follows the LLVM rules to name types and type aliases in CamelCase. However, often we have type aliases for template type parameters. Those type aliases are written in lower_case with trailing _t. So, for a template parameter D the corresponding type alias would be named d_t.

We prefer using type aliases over complex or repeated type-expressions.

Inline Functions

We prefer keeping the dependencies of our header files low to reduce the number of re-compiled compilation units if a single header changes. This also leads to functions being only forward-declared in headers and implemented in the corresponding source files. However, to sometimes it might be appropriate to inline small functions into the header.

We permit this for one- or two-liners where the implementation does not require additional #includes or benchmarks show significant performance gains by inlining a function into the header. However, we refrain from inlining functions if their content is subject to frequent changes.

Global Variables

We aim to avoid global variables as they are especially bug-prone. We allow constexpr globals. If you need to use a mutable global variable, consider using a getter-function with a static local variable instead. They do not suffer from undefined initialization-order.

File Header

Each code file inside PhASAR starts with a header of the form:

/******************************************************************************
 * Copyright (c) <year> Philipp Schubert.
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of LICENSE.txt.
 *
 * Contributors:
 *     <authors> and others
 *****************************************************************************/

Here, <year> and <authors> are placeholders.

This file header might be changed in the future.

Include Guard

As the time of this writing, PhASAR prefers include guards over #pragma once as the latter is a non-standard extension. This rule may change in the future.

The include-guard macro contains the full path to the header file starting from PhASAR's include/ folder. The macro is written in UPPER_CASE with directory separators (/) replaced by underscores (_). It ends with the _H suffix.

Enums

We prefer type-safe enum class over C-style enums. For enums with more than two variants, we prefer the macro-based generator pattern to not only generate the enum class itself, but the to_string function as well. As an example, see DataFlowAnalysisType.h.

If you want to use enums as bit-flags, use the EnumFlags header.

Library Dependencies

We avoid introducing new library dependencies as they add non-negligible overhead for maintenance. If possible, we use the utilities from LLVM and the STL. Otherwise, we prefer writing our own version of the desired utility, if the maintenance of the additional code does not exceed the maintenance for an additional library dependency.

Standard Library

Many utilities that PhASAR uses are present in both the STL and LLVM. We don't have a preference which of these to prefer. This heavily depends on the situation. We aim to use the best fitting data-structure for the respective tasks and oftentimes this leads us to prefer LLVM's data-structures over the ones from the STL. However, this stays an individual case decision.

Exceptions and Noexcept

We avoid the use of exceptions. This is, because of our heavy use of LLVM's functionality which makes PhASAR inherently exception-unsafe. However, in the periphery of PhASAR's core, exceptions are permitted but not encouraged.

Move constructors, move assignment and destructors must be noexcept.

Clone this wiki locally