Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: apply clang-tidy fixes #4015

Closed
wants to merge 16 commits into from
Closed

Conversation

caic99
Copy link
Member

@caic99 caic99 commented Apr 18, 2024

Reminder

  • Have you linked an issue with this pull request?
  • Have you added adequate unit tests and/or case tests for your pull request?
  • Have you noticed possible changes of behavior below or in the linked issue?
  • Have you explained the changes of codes in core modules of ESolver, HSolver, ElecState, Hamilt, Operator or Psi? (ignore if not applicable)

Linked Issue

Fix #3915

Unit Tests and/or Case Tests for my changes

  • A unit test which is expected to exit with assertion error has been fixed.

What's changed?

This PR applies clang-tidy rules on existing codes to improve code quality. I've carefully reviewed the modifications.

@caic99 caic99 marked this pull request as draft April 18, 2024 04:40
@caic99 caic99 marked this pull request as ready for review April 18, 2024 08:20
@haozhihan
Copy link
Collaborator

According to Commit message guidelines, I think using keyword Style might be more appropriate.

@caic99
Copy link
Member Author

caic99 commented Apr 19, 2024

According to Commit message guidelines, I think using keyword Style might be more appropriate.

This PR makes actual changes to the code.

Copy link
Collaborator

@mohanchen mohanchen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have looked through dozens of files, most of them look good to me. Howver, I don't understand some modifications, as can be seen with my comments.

source/module_base/abfs-vector3_order.cpp Outdated Show resolved Hide resolved
@@ -117,7 +117,7 @@ void scaled_sum(std::complex <double> c1, const ComplexArray &cd1,
ComplexArray &cd3);

/// out[i] = a1[i] * in2[i]
void point_mult(ComplexArray &a1, ComplexArray &in2, ComplexArray &out);
void point_mult(ComplexArray &in1, ComplexArray &in2, ComplexArray &out);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel the meaning has been changed here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name is changed in consistent with that in complexarray.cpp.

double *e{};
int lwork{};
std::complex<double> *work2{};
double* rwork{};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use nullptr here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using {} is identical, as it initializes the pointer to nullptr.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not looking identical ways of writing C++ codes, I just consider this new way of initializing variables make reading more difficult for some people, we should have a unified way. For example, double *rwork = nullptr;

namespace ModuleBase {

template <typename FPTYPE>
__inline__
FPTYPE __fact(const int n) {
FPTYPE _fact(const int n) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there any special reason to change the function name from __ to _

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The C++ standard reserves names starting with __.

@@ -187,7 +187,7 @@ class Chebyshev

public:
//Members:
int norder; // order of Chebyshev expansion
int norder{}; // order of Chebyshev expansion
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not initialize it will 0?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, why not write the code "int norder = 0" ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, why not write the code "int norder = 0" ?

Using bracelet is the only supported grammar for this fix initializing members in declaration. There is another fix available in your expected grammar, but the modifications will be much more.

source/module_base/math_sphbes.cpp Outdated Show resolved Hide resolved
bool&,
double&,
double&);
extern /* Subroutine */ void dcstep(double& /*stx*/,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks strange here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add variable names according to declaration to improve code readability.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't recommend writing "/* */"

source/module_base/parallel_global.cpp Outdated Show resolved Hide resolved
@jinzx10
Copy link
Collaborator

jinzx10 commented Apr 21, 2024

I went through the files in module_base, module_basis and module_cell. Apart from the mistaken removal of some gpu code in pw_basis_sup.cpp (which has been fixed in a commit), clang-tidy indeed tidies up a lot of code. Here's a brief list of what I record:

  1. add const& to function argument that are not altered in the body
    This can save many uncessary copy and is definitely a good practice.

  2. use std::move when copying variables that are no longer needed
    This can also prevent unnecessary copy (given that the move constructor / move assignment operator is available)

  3. delete "return" for void functions

  4. delete "void" in function parameter list
    These are basically a matter of style. Maybe we should choose one and stick with it. (PS: In C, a function declared as func() can take any arguments, while a function that takes no argument should be declared as func(void). In C++, func() is equivalent to func(void) so in some sense func(void) is more compatible and func() is more C++)

  5. reserve a std::vector before looping over push_back
    This is definitely a good practice if one can somehow know or estimate the final size in advance. If the objects are expensive to copy, or if there're a lots of elements to push back, reserving a vector could save a lot of time.

  6. replacing NULL or 0 with nullptr
    good practice by c++ standard

  7. more concise code when using bool variables
    If x is a bool, if statement can simply be if(x) instead of if (x == true) (or if(!x) instead of if (x == false)). I believe these two styles have no essential difference as the compiler would be smart enough to generate the same code, but I personally do prefer the shorter one. Another case is

if (some_condition)
    x = true;
else
    x = false;

which can be simply

x = some_condition;
  1. use the member function empty() when checking if a stl container is empty
    Technically empty() provided by the container is the fastest way to check if a container is empty. Take vector as an example, x.size() == 0 actually involves two steps: (1) subtracting "begin" from "finish" and (2) compare the result with 0, while empty() simply performs one step "begin == finish". Though the difference is marginal and might be optimized by the compiler, I think it's always better to stick with the better one.

  2. make member functions static whenever possible
    This is important for unit test. Static member function can be called (thus tested) without constructing object.

  3. initialize POD type variables (int, double, pointer, ...)
    This is very important to avoid many unexpected behaviors. An uninitialized int/double/pointer could be any random value. What's even worse is that the piece of memory allocated to those uninitialized variables are used before and is occupied by some meaingful value. In that case, even if the code has some logical error, such uninitialized variables might accidentally make things work. There's actually a fresh example in this PR: in source/module_cell/test/read_pp_test.cpp, HeaderErr2015, an extra "EXPECT_DEATH" has to be added to the tested function which is supposed to fail. The reason that the function could normally terminate before this PR is that the test involves an assertion on an uninitialized variable which was set in the last unit test HeaderErr2013. Even though test objects are intialized for each test in unit testing, uninitialized variables could actually "inherit" values from previous tests if memory are allocated the same way.

  4. no need to initialize a string with "" (and other stl containers to explicit empty)
    As opposed to POD types, default intializations of stl containers are all properly handled - e.g., std::string is default initialized to "" - so there's no need to specify.

  5. when finding a single character in a string, make sure to pass a char instead of a string with one character:

str.find(':'); // good
str.find(":"); // not as good, though practically the difference might be neglible
  1. in an if-else statement, removing the "else-branch" if the "if-branch" contains something that terminates the code flow:
    for example, clang-tidy constantly replaces
if (condition)
    return some_variable;
else
    do_something_else();

with

if (condition)
    return some_variable;
do_something_else();

I think this is another matter of style which I have no particular preference. However, if both branches return something, I personally prefer the ternary operator:

return (condition) ? A : B;

For the three modules I was assigned, I think the changes made by this PR looks good (with some style issue that may or may not need discussion). The only real issue is that this PR messes up quite a few indentation, which might be fixed by another PR of clang-format, I guess?

@caic99
Copy link
Member Author

caic99 commented Apr 22, 2024

The only real issue is that this PR messes up quite a few indentation, which might be fixed by another PR of clang-format, I guess?

Running clang-format will modify codes significantly, so this PR does not execute it.

@caic99 caic99 requested a review from mohanchen April 22, 2024 03:00
Copy link
Collaborator

@kirk0830 kirk0830 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have reviewed files in module_hamilt_pw, module_io, module_psi.
There are mainly several kinds of code polishment I have observed:

  1. change "pass by value" to "pass by ref" or "pass by value then swap".
  2. add static keyword ahead of function that does not rely on member variables.
  3. delete useless return in void function.
  4. change some 0 and 1 to false or true, correspondingly, avoid implicit type conversion
  5. use list initialization on PART of member variables.
  6. remove the use of operator ?: in some boolean assignment cases.
  7. add annotation behind namespace.
  8. make nomenclature of varialbles consistent.
  9. delete redundant if not nullptr sentence before deallocating one pointer
  10. change the default initialization value NULL for pointer to nullptr

However,

  1. it (clang-tidy) indeed removed some annotation by mistake especially at the end of functions.
  2. the indent seems to be not well-treated, but I guess it is because the mixed use of Tab and whitespaces
  3. not fully change the if-else logic, like in psi_initializer_atomic.cpp:
std::complex<double> phase_factor(double arg, int mode)
{
    if(mode == 1) return std::complex<double>(cos(arg),0);
    if (mode == -1) return std::complex<double>(0, sin(arg));
    else if (mode == 0) return std::complex<double>(cos(arg), sin(arg));
// can also be `if` instead of `else if`
    else return std::complex<double>(1,0);
// can directly `return`
}

source/module_io/binstream.cpp Outdated Show resolved Hide resolved
source/module_io/cal_dos.cpp Outdated Show resolved Hide resolved
source/module_io/cal_dos.h Show resolved Hide resolved
source/module_io/istate_envelope.h Show resolved Hide resolved
@@ -26,7 +26,7 @@ class Meta<OperatorPW<T, Device>> : public OperatorPW<T, Device>
private:
using Real = typename GetTypeReal<T>::type;
public:
Meta(Real tpiba2_in,
Meta(Real tpiba_in,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure but it seems tpiba is not equivalent with tpiba2, the latter seems to be square of the former.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree

@@ -35,8 +35,8 @@ class Velocity
*/
void act(const psi::Psi<std::complex<double>>* psi_in,
const int n_npwx,
const std::complex<double>* tmpsi_in,
std::complex<double>* tmhpsi,
const std::complex<double>* psi0,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems not a good idea...

source/module_hamilt_pw/hamilt_pwdft/stress_func_cc.cpp Outdated Show resolved Hide resolved
@caic99
Copy link
Member Author

caic99 commented Apr 24, 2024

Hi @mohanchen @kirk0830 ,
I've replied the conversations and modified codes w.r.t. our discussion. Would you please kindly review the PR? Feel free to comment if you have further questions. Many thanks.

@caic99 caic99 requested a review from kirk0830 April 24, 2024 09:35
@mohanchen
Copy link
Collaborator

Hi @mohanchen @kirk0830 , I've replied the conversations and modified codes w.r.t. our discussion. Would you please kindly review the PR? Feel free to comment if you have further questions. Many thanks.

Hi Cun, though most of the updates look good to me. However, I am deeply concerned about some modifications that change the parameter names, and the amount of modifications of codes is huge (522 files!). In addition, although I ask some questions, I don't get the answers I want (not the explanations for C++ grammar).

@caic99
Copy link
Member Author

caic99 commented Apr 28, 2024

Hi Cun, though most of the updates look good to me. However, I am deeply concerned about some modifications that change the parameter names, and the amount of modifications of codes is huge (522 files!). In addition, although I ask some questions, I don't get the answers I want (not the explanations for C++ grammar).

Hi @mohanchen ,
I fully understand your concern and am agree with you.
This PR acts as an experiment to provide a possible solution for using automatic tools to improve code quality, and actually I'm not expecting it will be merged into trunk. However, I think the most important point here is that providing us a chance to discuss the rules in detail to maintain code quality.

@mohanchen
Copy link
Collaborator

Hi Cun, though most of the updates look good to me. However, I am deeply concerned about some modifications that change the parameter names, and the amount of modifications of codes is huge (522 files!). In addition, although I ask some questions, I don't get the answers I want (not the explanations for C++ grammar).

Hi @mohanchen , I fully understand your concern and am agree with you. This PR acts as an experiment to provide a possible solution for using automatic tools to improve code quality, and actually I'm not expecting it will be merged into trunk. However, I think the most important point here is that providing us a chance to discuss the rules in detail to maintain code quality.

Thanks, I understand your thoughts better now. How about we close this PR but we label it as 'Useful Information', then we can use this as a reference for further discussion of how to make changes as we expect. @caic99

@mohanchen mohanchen added Useful Information Useful information for others to learn/study and removed Plans labels May 8, 2024
@caic99 caic99 closed this May 8, 2024
@caic99
Copy link
Member Author

caic99 commented May 27, 2024

Hi all,
I've updated the clang-tidy rules discussed above.

in an if-else statement, removing the "else-branch" if the "if-branch" contains something that terminates the code flow:
for example, clang-tidy constantly replaces

I've removed this rule removing else after a return statement. This is indeed optional, and will making incomplete changes.

the indent seems to be not well-treated

This is the job of clang-format, and we may discuss it with another issue.


However, I still insist that some fixes are necessary, which we've also discussed above (and I kept them unresolved to show more details):

  1. Consistency between declaration and definition
  2. Zero-initialize variables

By consolidating a rule and applying them on each PR, the code quality is able to be assured and improved during refactor.

caic99 added a commit to caic99/abacus-develop that referenced this pull request May 27, 2024
mohanchen added a commit that referenced this pull request Jun 13, 2024
* CI: add pre-commit.ci to apply clang-format and clang-tidy fixes

* do pre-commit fixes first

* install clang utils

* apply fixes only on changed files

* fetch historical commits to get the changed files

* test if pre-commit could fix sabotaged format

* update pre-commit config

* apply fixes

* commit changes after apply them

* commit changes using pre-commit.ci lite

* try to fix SSL error using pre-commit.ci lite

* [pre-commit.ci lite] apply automatic fixes

* format arguments

* add docs on pre-commit hook

* Update clang-format config.

ABACUS uses some functions with a long function name and a long parameter list.

Current setup will generates ugly parameter list with each parameters indented by many spaces. Plus, it is unable to use a customized layout for e.g. putting x, y, and z value in the same line.

After discussion, we agree to disable those settings, leaving developers free to chose their own flavor.

* Update clang-tidy config.

#4015

* [pre-commit.ci lite] apply automatic fixes

* Update .pre-commit-config.yaml

* Update .clang-tidy according to the meeting

---------

Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Mohan Chen <mohan.chen.chen.mohan@gmail.com>
Co-authored-by: Haozhi Han <haozhi.han@outlook.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Useful Information Useful information for others to learn/study
Projects
None yet
Development

Successfully merging this pull request may close these issues.

clang-format and clang-tidy is not employed
5 participants