Skip to content

Source code formatting conventions

John W. Peterson edited this page Jun 20, 2023 · 35 revisions

The contrib/bin/reindent.sh script is provided to automatically control the amount and type of indentation used in libMesh source files. It isn't perfect, but it's pretty good, and if you run this script on the files you've modified before submitting them, we won't have to run it on them later, artificially changing line ownership statistics.

Note: The current codebase does not exactly follow all the conventions below! We try to fix things as we come across them in the process of doing other work, but it's very likely a cursory examination will uncover non-compliant code.

Whitespace/editor

  • Tab characters are not allowed in indentation, use only spaces. Most editors have a way of enforcing this convention. In Emacs, you add the following to your .emacs file:

    (setq-default indent-tabs-mode nil)
    

    In Vim, you can add to .vimrc:

    set expandtab
    
  • No trailing whitespace is allowed. Again, most editors have a way of removing trailing whitespace either manually (Emacs: M-x delete-trailing-whitespace) or automatically, add to your .emacs file:

    (add-hook 'c-mode-hook
      (lambda () (add-to-list 'write-file-functions 'delete-trailing-whitespace)))

Vim has similar options: :%s/\s+$ autocmd FileType c,cpp autocmd BufWritePre :%s/\s+$//e

  • Every file should end with a single newline. That is, in the output of git diff, you should not see:

    \ No newline at end of file
    
  • There is no maximum (or minimum) allowed line length, but around 125 characters is probably pushing the limits of readability. Use your best judgement, shorter is not necessarily always better either.

Naming

  • Class names begin with a capital letter and use camelcase, e.g. MeshBase, FEMFunction, etc.

  • Functions names are lowercase and use underscores to separate the words, e.g. get_boundary_info(), make_node_proc_ids_parallel_consistent().

  • Variable names also use the lowercase/underscore convention. Private and protected members of classes are prefixed with a single leading underscore, e.g. unsigned int _foo;.

Documentation

  • Use Doxygen-style comment blocks, including \author and \date directives if desired, at the top of classes and functions. Use C++ style comments for everything else.
    /**
     * This class is ground-breaking.
     *
     * \author Bob
     * \date 2015
     * \brief A brief description of what this class does.
     */
    class BigBertha
    {
    public:
      /**
       * Do not simply say "Constructor". Tell what the constructor does.
       */
      BigBertha();
    
      /**
       * \returns A brief description of the return value starting with a capital letter.
       *
       * \note A special note that you would like to stand out from the rest of the
       * documentation.
       *
       * \deprecated If this function is deprecated, briefly describe why.
       *
       * Additional description of the function, use typewriter font when referring
       * to parameters like \p time.
       */
      bool drill(double time);
    };

Spacing and indentation

  • Leave one space on either side of the * or & character in pointer and reference declarations, respectively. Do not leave a space when dereferencing or taking the address of a variable.

    unsigned int x = 42;
    unsigned int * px = &x;
    unsigned int & rx = *px;
  • Indent streaming print statements on the stream injection (<<) operator. (This convention applies to long lines only, multiple << operators on a single, short line is also OK.)

    oss << std::fixed
        << std::setprecision(4)
        << std::setw(tot_time_col_width)
        << std::left
        << summed_total_time;
  • All libMesh classes are declared in namespace libMesh. Indent zero spaces in namespaces, and two spaces in classes, except for access control (public, protected, private) keywords.

    namespace libMesh
    {
    
    class Foo
    {
    public:
      Foo (unsigned int bar) :
        _bar(bar)
      {}
    };
    
    }
  • Leave at least three blank lines between function body definitions in .C files. This makes it easier to see where one function body ends and the next begins at a quick glance.

    void BigBertha::drill()
    {
      if (!working)
        backup();
    }
    
    void BigBertha::backup()
    {
      libmesh_error();
    }

Function prototypes

  • Template declarations should appear on a separate line.

  • The function parameter list should begin on the same line as the function name.

  • Return type may be on a separate line if desired.

  • One space between function name and opening parenthesis, no space after opening parenthesis.

  • For functions with long parameter lists, use one line per parameter (otherwise all on one line).

  • Indent each parameter to the beginning of the parameter on previous line.

  • Functions taking no arguments should omit the void keyword from the parameter list.

    template<typename OutputShape>
    std::unique_ptr<FEGenericBase<OutputShape>>
    build_new_fe (const FEGenericBase<OutputShape> * fe,
                  const Point & p,
                  const Real tolerance = TOLERANCE) const;
  • One space after commas in single-line function parameter lists:

    void foo (int bar, float baz, char bob);

"for", "if", "while"

  • Single-line bodies should not use curly braces.
  • One space between the keyword and opening parenthesis.
  • Start curly braces on a new line.
  • Indent opening curly brace two spaces. (This is the current behavior of reindent.sh, but it may be changed at some point in the future.)
  • Put spaces after semi-colons in for-loop declaration clauses.
    for (unsigned int i=1; i<=N; ++i)
      {
        sum += i;
        prod *= i;
      }

Debugging

  • Employ only one code statement per line of file, i.e.

    a = foo();
    b = bar();

    and not:

    a = foo(); b = bar();
  • Terser code is generally preferred, but not at the expense of debugging flexibility. Hence, while it may be possible to write e.g.:

    foo(bar());

    from a debugging standpoint, we would also accept (and encourage!) the following:

    b = bar();
    foo(b);

Git commit message format

Git commit messages should attempt to follow these formatting guidelines as closely as possible, and should definitely have:

  1. A short (50 chars or less) subject line.
  2. A blank line following the subject line.
  3. An issue reference number, if applicable.