tests: remove fifteen #define private public — by deleting dead hacks and by passing INPUT values explicitly - #7980
Merged
mohanchen merged 2 commits intoSep 17, 2026
Conversation
Four of these macros were vestigial: the tests inside them touch no private
or protected member of any class in the headers they cover.
- klist_test_para.cpp the only mentions of K_Vectors::spin_mult and
mpi_k() are in comments; koffset is a local array,
not the private member of the same name
- qlist_test.cpp every member it reads (nkstot, nkstot_nospin, wk,
kvec_c, kvec_d, kc_done, kd_done, is_mp) is public
in ModuleCell::ReciprocalGrid; QList's own privates
(nirr_, irrep_modes_, little_group_) are untouched
- sepcell_test.cpp already goes through the public getters get_ntype(),
get_omega(), get_tpiba2(), get_sep_enable() and
get_seps(); sep_enable appears only in comments
- test_output_hcontainer_consistency.cpp
uses none of HContainer's, Output_HContainer's or
Read_HContainer's private members
The fifth, test_init_dm_from_file.cpp, read DensityMatrix::_DMR directly in
seven places while already calling the public get_DMR_vector() three lines
away in the same tests. get_DMR_vector() returns exactly _DMR, so those seven
reads are now routed through it.
No production code changes and no assertion changes.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…removing ten access hacks
Ten `#define private public` / `#define protected public` existed only so a
test could write the private half of PARAM. None of them is replaced by a
friend declaration: each is removed by making the dependency explicit, so the
diff removes 31 PARAM/GlobalV occurrences and adds 5 (net_delta = -26).
Group 1 -- the dependency was already injected; the test was routing through
the global for no reason. No production change at all:
- propagator_test{1,2,3}: Propagator's constructor already takes
`const double& dt`. Each test wrote PARAM.input.mdp.md_dt and then read
PARAM.mdp.md_dt straight back to pass it in. Now a local `md_dt`, and the
(henceforth unused) parameter.h include is dropped -- propagator.h already
provides ModuleBase::AU_to_FS via source_base/constants.h.
- single_r_io_test: `PARAM.sys.nlocal = 99` was dead. single_r_io.cpp has no
PARAM reference at all and takes nlocal from pv.get_global_row_size(),
which this test stubs to return 5.
- read_wfc_nao_test: read_wfc_nao() already takes the directory as its first
argument; the test wrote PARAM.sys.global_readin_dir and passed it back in.
Now a local `readin_dir`.
Group 2 -- the production code really did read PARAM, so the value is now a
parameter:
- write_dmk() takes `const std::string& dmk_dir`, mirroring its sibling
read_dmk() which already does. write_dmk.cpp is now PARAM-free and drops
the include. Its one caller (ctrl_scf_lcao.cpp) already holds a
`global_out_dir` local, so the call site adds no PARAM reference.
- K_Vectors gains `set_spin_mult()` next to the existing set_nks() /
set_nkstot() / set_nkstot_nospin(); the public getter get_spin_mult()
already existed, so this completes an incomplete setter group and lets
write_dmk_test stop assigning kv.spin_mult directly.
- write_eig_iter() and write_eig_file() take nbands and nspin, and
write_eig_file() takes `const std::string& out_dir`. Both callers are in
esolver_ks.cpp, which already holds an injected `inp_`, so nbands/nspin
cost no PARAM reference; only out_dir adds one.
- write_eig_occ_test's PARAM.sys.nbands_l write was dead (no source or
library in that target reads it) and its PARAM.input.bndpar read is now a
local mirroring the Input_para default of 1, so the test no longer depends
on an INPUT default.
No default arguments were added. No assertion or expected value changed.
write_eig_occ.cpp still reads PARAM for out_alllog, calculation and
mdp.md_restart -- no test drives those, so injecting them would only cost
budget.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Critsium-xy
force-pushed
the
refactor/drop-vestigial-access-hacks
branch
from
September 17, 2026 06:32
92ae395 to
b223fc1
Compare
This was referenced Sep 17, 2026
mohanchen
approved these changes
Sep 17, 2026
Zanthoxylum
pushed a commit
to Zanthoxylum/abacus-develop
that referenced
this pull request
Sep 17, 2026
This was referenced Sep 18, 2026
Merged
mohanchen
added a commit
that referenced
this pull request
Sep 18, 2026
…to zero access hacks (#7987) klist_test reached into K_Vectors through `#define private public`. It turned out that only four of the things it touches actually needed anything, and two needed nothing at all. Needed wrappers -- set() is the single production entry point and drives these in order, while the test exercises them one stage at a time because most of the KPT-file parsing paths are only reachable that way: read_kpoints_for_testing() 27 call sites renew_for_testing() 8 reduce_by_symmetry_for_testing() 2 set_kup_and_kdw_for_testing() 5 Needed nothing: - spin_mult, 37 sites (36 writes, 1 read), already has public get_spin_mult() and set_spin_mult(); the setter was added in #7980 for write_dmk_test and covers every one of them. - koffset, 4 sites. Both Monkhorst_Pack() and read_kpoints() take the offset as an argument, and the 27 read_kpoints call sites already pass a local `const double koffset[3]`. Only two setup blocks wrote the member and then handed it straight back to Monkhorst_Pack(), so those now use a local array too and the member is not touched from the test at all. The remaining 155 accesses in the file (get_nkstot, kvec_c, kvec_d, wk, kc_done, kd_done, set_both_kvec, nmp, isk, ...) were public throughout and are unchanged. I checked all six K_Vectors objects in the file -- kv, kv1 and kv_test1..4 -- and the other classes the macro covered: nothing else private is used, and pseudo.h, atom_spec.h, atom_pseudo.h and magnetism.h have no private sections at all. Worth stating for review: the four wrappers are public entry points that only the tests use, in the style of set_density_rotations_for_testing() in symm_rotation.h, and carry a comment saying production code must keep going through set(). read_kpoints() in particular is a substantial piece of behaviour with 27 tests behind it; if review would rather see it simply become part of the public interface, that is a one-line change and the wrapper can go. No production logic changed. No assertion or expected value changed. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Mohan Chen <mohanchen@pku.edu.cn>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this does
Removes 15 of the 69
#define private public/#define protected publicmacros in
source/(69 → 54), in two commits. Nofrienddeclaration isadded anywhere — every macro is removed either because it was never needed, or
by making the dependency explicit, which is why the diff reduces global-state
coupling instead of relocating it.
PARAM/GlobalV/GlobalCledger for the whole PR: added 5, removed 31,net_delta = −26.
Commit 1 — five macros no test actually needed
Four were vestigial: the tests inside them access no private or protected member
of any class in the headers the macro covers.
source_cell/test/klist_test_para.cppK_Vectors::spin_multandmpi_k()are in comments.koffsetat lines 209/333 is a localconst double koffset[3], not the private member of the same name.source_cell/test/qlist_test.cppnkstot,nkstot_nospin,wk,kvec_c,kvec_d,kc_done,kd_done,is_mp— is public inModuleCell::ReciprocalGrid.QList's own privates (nirr_,irrep_modes_,little_group_,interpolate_q_between,get_irreps) are never touched.source_cell/test/sepcell_test.cppget_ntype(),get_omega(),get_tpiba2(),get_sep_enable(),get_seps().sep_enableappears only inside a comment.source_lcao/test/test_output_hcontainer_consistency.cppHContainer,Output_HContainerorRead_HContainer.source_lcao/test/test_init_dm_from_file.cppDensityMatrix::_DMRdirectly in 7 places while calling the publicget_DMR_vector()in the same tests.get_DMR_vector()returns exactly_DMR(density_matrix.h:191), so those 7 reads now go through it.The three
source_cellmacros also coveredpseudo.h,atom_spec.h,magnetism.handatom_pseudo.h, which have no private sections at all —including them under the macro never did anything.
Commit 2 — ten macros that existed only to write the private half of
PARAMGroup A: the dependency was already injected; the test routed through the global for no reason
No production change at all in this group.
propagator_test{1,2,3}(6 macros) —Propagator's constructor alreadytakes
const double& dt. Each test wrotePARAM.input.mdp.md_dtand then readPARAM.mdp.md_dtstraight back to pass it in. Now a localmd_dt. Thenow-unused
parameter.hinclude is dropped;propagator.halready providesModuleBase::AU_to_FSviasource_base/constants.h, andsource_base/global_variable.his included directly for theGlobalV::ofs_runningthese tests genuinely use.single_r_io_test(1) —PARAM.sys.nlocal = 99was dead.single_r_io.cpphas noPARAMreference at all and takesnlocalfrompv.get_global_row_size(), which this test stubs to return 5.read_wfc_nao_test(1) —read_wfc_nao()already takes the directory asits first argument; the test wrote
PARAM.sys.global_readin_dirand passedit straight back in. Now a local
readin_dir.Group B: the production code really did read
PARAM, so the value became a parameterwrite_dmk()now takesconst std::string& dmk_dir, mirroring its siblingread_dmk()in the same header, which already does.write_dmk.cppis nowPARAM-free and drops the include. Its one caller(
ctrl_scf_lcao.cpp:199) already holds aglobal_out_dirlocal, so the callsite adds no
PARAMreference.K_Vectors::set_spin_mult()added next to the existingset_nks()/set_nkstot()/set_nkstot_nospin(). The public getterget_spin_mult()already existed, so this completes an incomplete setter group and lets
write_dmk_teststop assigningkv.spin_multdirectly — the second reasonthat file needed the macro.
write_eig_iter()andwrite_eig_file()takenbandsandnspin, andwrite_eig_file()takesconst std::string& out_dir. Both callers are inesolver_ks.cpp, which already holds an injectedinp_, sonbands/nspincost no
PARAMreference.write_eig_occ_test'sPARAM.sys.nbands_lwrite was dead (no source orlibrary in that target reads it — the readers are in
source_estate,source_psiandsource_pw), and itsPARAM.input.bndparread is now alocal mirroring the
Input_paradefault of1, so the test no longer dependson an INPUT default.
No default arguments were added (governance blocks that, and
print_forcealready showed why: adding one is not an option). No assertion or expected
value changed.
Governance warnings, with rationale
net_delta = −26.esolver_ks.cpp:328(+1) is the only genuinely new reference:PARAM.globalv.global_out_dirat thewrite_eig_filecall site. This is thecomposition root deliberately absorbing a global read so the leaf writer stays
clean — the same direction as source_relax: pass INPUT values explicitly instead of reading PARAM, removing the test access hacks it caused #7921.
write_eig_occ_test.cpp:66,67(+4) are pre-existingGlobalV::NPROC/GlobalV::MY_RANKarguments toParallel_Global::init_pools; reflowing thatcall to pass a local
bndparmakes the checker count those lines as added.write_eig_occ.hgains<string>, required by the newconst std::string& out_dirparameter. No forward declaration is possible forstd::stringhere.docs/update is required anddocs/parameters.yamlneeds no regeneration.Not in this PR
source_io/module_json/test/para_json_test.cpp— reads the private staticJson::AbacusJson::doc89 times (77 asdoc[...]subscripts). Its onlypublic path is
write_to_json(filename). Also note this target builds onlyunder
ENABLE_RAPIDJSON.source_estate/module_dm/test/test_dm_r_init.cpp— asserts onDensityMatrix::_DMR_save[0].size()in 2 places; needs a production accessor.source_io/test/outputlog_test.cpp—out_levelandnspinare cheap(1 call site each), but its third key
test_forcelives inprint_force,which has ~45 call sites across
force_pw.cpp,sto_forces.cpp,force_stress_assemble.cpp,md_func.cppandesolver_{dp,lj,nep}.cpp.Injecting it would add ~45
PARAMreferences and block on the budget, allfor one
std::cout << table;debug echo. It needs its own PR paired with areal reduction elsewhere.
Continues #7921 / #7949 / #7952 / #7953 / #7963 / #7964 / #7965 / #7966 / #7967
and keeps their scope rule: a file is either taken fully off the macro or left
alone.
Verification
Remote Linux box,
cmake -B build -G Ninja -DBUILD_TESTING=ON -DENABLE_LCAO=ON -DENABLE_MPI=ON -DENABLE_OPENMP=ON:ninja: no work to doon a follow-up full buildMODULE_CELL_klist_test_para1,MODULE_CELL_qlist_test,MODULE_CELL_SEP_CELL_TEST,MODULE_LCAO_init_dm_from_file_test,MODULE_LCAO_output_hcontainer_consistency_test,MODULE_LCAO_tddft_propagator_test,MODULE_IO_single_R_test,MODULE_IO_read_wfc_nao_test,MODULE_IO_write_dmk,MODULE_IO_write_eig_occ_test, plusabacus_basic_paraagent_governance_check.py --base upstream/develop --head HEAD: zeroblockers, no access-hack ratchet finding (15 removed, 0 added)
🤖 Generated with Claude Code