Skip to content

Cleanup Cppcheck warnings continued#11514

Draft
dareumnam wants to merge 4 commits intodevelopfrom
cppcheck_continued
Draft

Cleanup Cppcheck warnings continued#11514
dareumnam wants to merge 4 commits intodevelopfrom
cppcheck_continued

Conversation

@dareumnam
Copy link
Copy Markdown
Collaborator

@dareumnam dareumnam commented Apr 10, 2026

Pull request overview

  • Cleanup Cppcheck warnings regarding constVariableReference, knownConditionTrueFalse, and multiCondition

Description of the purpose of this PR

Pull Request Author

  • Title of PR should be user-synopsis style (clearly understandable in a standalone changelog context)
  • Label the PR with at least one of: Defect, Refactoring, NewFeature, Performance, and/or DoNoPublish
  • Pull requests that impact EnergyPlus code must also include unit tests to cover enhancement or defect repair
  • Author should provide a "walkthrough" of relevant code changes using a GitHub code review comment process
  • If any diffs are expected, author must demonstrate they are justified using plots and descriptions
  • If changes fix a defect, the fix should be demonstrated in plots and descriptions
  • If any defect files are updated to a more recent version, upload new versions here or on DevSupport
  • If IDD requires transition, transition source, rules, ExpandObjects, and IDFs must be updated, and add IDDChange label
  • If structural output changes, add to output rules file and add OutputChange label
  • If adding/removing any LaTeX docs or figures, update that document's CMakeLists file dependencies
  • If adding/removing any output files (e.g., eplustbl.*)
    • Update ..\scripts\Epl-run.bat
    • Update ..\scripts\RunEPlus.bat
    • Update ..\src\EPLaunch\ MainModule.bas, epl-ui.frm, and epl.vbp (VersionComments)
    • Update ...github\workflows\energyplus.py

Reviewer

  • Perform a Code Review on GitHub
  • If branch is behind develop, merge develop and build locally to check for side effects of the merge
  • If defect, verify by running develop branch and reproducing defect, then running PR and reproducing fix
  • If feature, test running new feature, try creative ways to break it
  • CI status: all green or justified
  • Check that performance is not impacted (CI Linux results include performance check)
  • Run Unit Test(s) locally
  • Check any new function arguments for performance impacts
  • Verify IDF naming conventions and styles, memos and notes and defaults
  • If new idf included, locally check the err file and other outputs

@dareumnam dareumnam added the Defect Includes code to repair a defect in EnergyPlus label Apr 10, 2026
@dareumnam dareumnam changed the title Fix a logic/scoping issue in SimAirServingZones.cc Cleanup CppCheck warnings continued Apr 10, 2026
@dareumnam dareumnam changed the title Cleanup CppCheck warnings continued Cleanup Cppcheck warnings continued Apr 10, 2026
@dareumnam dareumnam marked this pull request as draft April 10, 2026 13:56
@dareumnam dareumnam added DoNotPublish Includes changes that shouldn't be reported in the changelog and removed Defect Includes code to repair a defect in EnergyPlus labels Apr 10, 2026
int numNoDepend = -1;
int loopCount = 0;
while ((numNoDepend != 0) || (loopCount > 100000)) {
while ((numNoDepend != 0) && (loopCount < 100000)) {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I think this loop condition is flipped.
With while ((numNoDepend != 0) || (loopCount > 100000)), the loop would continue once loopCount exceeds the limit, so the post-loop check if (loopCount > 100000) (line 2411) becomes unreachable.
This probably wants && with a max-iteration guard instead, like while ((numNoDepend != 0) && (loopCount < 100000)).

const auto &FinalSysSizing(state.dataSize->FinalSysSizing);
auto &EvapCond(state.dataEvapCoolers->EvapCond);
auto &thisEvapCond(EvapCond(EvapCoolNum));
auto &thisEvapCond(state.dataEvapCoolers->EvapCond(EvapCoolNum));
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

EvapCond itself is only used once and is never modified, and the actual mutable object is thisEvapCond. Rather than making EvapCond a const, it may be cleaner to remove that alias entirely and bind thisEvapCond directly to state.dataEvapCoolers->EvapCond(EvapCoolNum).

if (!RunFlag) {
return;
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The second if (!RunFlag) here is unreachable since the earlier if (!RunFlag) in line 1590 already returns from the function. By the time execution gets here, RunFlag must be true, so this check can be removed.

}
if (state.dataEnvrn->PrintEnvrnStampWarmup) {
if (state.dataReportFlag->PrintEndDataDictionary && state.dataGlobal->DoOutputReporting) {
if (state.dataReportFlag->PrintEndDataDictionary) {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

DoOutputReporting is already guaranteed to be true by the enclosing else if condition (line 3356), so the inner check is redundant here. I removed the repeated state.dataGlobal->DoOutputReporting from the nested if condition.

print(state.files.mtr, "{}\n", EndOfHeaderString);
state.dataReportFlag->PrintEndDataDictionary = false;
}
if (state.dataGlobal->DoOutputReporting) {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Same, the repeated state.dataGlobal->DoOutputReporting can be removed.

}
if (state.dataEnvrn->PrintEnvrnStampWarmup) {
if (state.dataReportFlag->PrintEndDataDictionary && state.dataGlobal->DoOutputReporting && !state.dataHVACMgr->PrintedWarmup) {
if (state.dataReportFlag->PrintEndDataDictionary && !state.dataHVACMgr->PrintedWarmup) {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Same as the HeatBalanceManager.cc cases. DoOutputReporting is already guaranteed to be true by the enclosing else if condition (line 479), so the inner checks are redundant here and in the line 493. I removed the repeated state.dataGlobal->DoOutputReporting from the nested if condition.

PreviousMaxiumHumidOrDehumidOutput = latentRoomORZone;
}
} else {
if (!DidWeMeetLoad) {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

!DidWeMeetLoad is already guaranteed by the enclosing if (!DidWeMeetLoad && !DidWeMeetHumidificaiton) in line 1544, so the nested if (!DidWeMeetLoad) is redundant here and can be removed.

CurrentOperatingSettings[1] = oStandBy;
} else {
// if we partly met the load then do the best we can and run full out in that optimal setting.
if (!DidWeMeetLoad && DidWePartlyMeetLoad) {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Same here.

if (!RunFlag) {
DesiredMassFlowRate = 0.0;

} else if (RunFlag && this->InternalFlowControl) {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

RunFlag is already implied in these else if branches because the preceding if (!RunFlag) (line 1191) has already failed. The four conditions here can be simplified by removing RunFlag &&.


if (ErrorsFound) {
ShowFatalError(state, "Preceding sizing errors cause program termination");
}
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

ErrorsFound is initialized to false and never updated in this routine, so the final if (ErrorsFound) block is unreachable.

int SurfDetails = 0;
bool SurfVert = false;
bool SurfDet = false;
bool DXFDone = false;
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

These three are initialized to false.


General::ScanForReports(state, "Surfaces", DoReport, "Vertices");
if (DoReport) {
if (!SurfVert) {
Copy link
Copy Markdown
Collaborator Author

@dareumnam dareumnam Apr 10, 2026

Choose a reason for hiding this comment

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

These flags here and below are being checked in places where they are still guaranteed to be false, so the nested if (!flag) branches are redundant.

General::ScanForReports(state, "Surfaces", DoReport, "VRML", Option1, Option2);
if (DoReport) {
bool VRMLDone = false;
if (!VRMLDone) {
Copy link
Copy Markdown
Collaborator Author

@dareumnam dareumnam Apr 10, 2026

Choose a reason for hiding this comment

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

VRMLDone is declared locally inside the block and never set to true, so its else branch below is unreachable. the if-else condition can be removed.

@@ -3464,7 +3464,7 @@ namespace PlantPipingSystemsManager {
if (CellXIndex <= MinXIndex || CellZIndex <= MinZIndex) { // Ground surface
Copy link
Copy Markdown
Collaborator Author

@dareumnam dareumnam Apr 10, 2026

Choose a reason for hiding this comment

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

If CellXIndex <= MinXIndex || CellZIndex <= MinZIndex is false, then both indices must already be greater than the minimum bounds, so the following else if (CellXIndex >= MinXIndex || CellZIndex >= MinZIndex) (line 3467) is always true. This can be simplified to a plain else.

auto &AirChillerSet = state.dataRefrigCase->AirChillerSet;
for (int CoilSetIndex = 1; CoilSetIndex <= state.dataRefrigCase->NumRefrigChillerSets; ++CoilSetIndex) {
AirChillerSet(CoilSetIndex).CalculateAirChillerSets(state);
state.dataRefrigCase->AirChillerSet(CoilSetIndex).CalculateAirChillerSets(state);
Copy link
Copy Markdown
Collaborator Author

@dareumnam dareumnam Apr 10, 2026

Choose a reason for hiding this comment

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

I just removed the one-use AirChillerSet alias and called it directly. That gets rid of the constVariableReference warning and makes it a bit clearer that the element itself is being mutated.


// Sum up all the case and walk-in loads served by the secondary loop
if (this->NumCases > 0) {
auto &RefrigCase = state.dataRefrigCase->RefrigCase;
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Removed the one-use RefrigCase alias and accessed the element directly. This clears the constVariableReference warning and keeps the mutating call explicit.

} // CaseNum
} // NumCases > 0
if (this->NumWalkIns > 0) {
auto &WalkIn = state.dataRefrigCase->WalkIn;
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Removed the one-use WalkIn alias and accessed the element directly. This clears the constVariableReference warning and keeps the mutating call explicit.

}

if (state.dataRefrigCase->NumSimulationWalkIns > 0) {
auto &WalkIn = state.dataRefrigCase->WalkIn;
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Removed the one-use WalkIn alias and accessed the element directly. This clears the constVariableReference warning and keeps the mutating call explicit.


// NOTE: Performed before checking min and max constraints to mimic original implementation
// in ManagerControllers()
if (RootFinderData.MinPoint.DefinedFlag && RootFinderData.MaxPoint.DefinedFlag) {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

RootFinderData.MinPoint.DefinedFlag is already guaranteed by the enclosing condition here,

if (CheckMinConstraint(state, RootFinderData)) {
RootFinderData.StatusFlag = RootFinderStatus::OKMin;
RootFinderData.XCandidate = RootFinderData.MinPoint.X;
if (CheckMinConstraint(state, RootFinderData)) {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

so this nested check is redundant and can be removed.


} else if (is_any_of(NextChar, "+-*/^=<>@|&")) {
// Parse an operator token
if (NextChar == '-') {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

(NextChar == '-') is already guaranteed here

}
}

if ((NumOperands == 5) && (NumTokens >= 6)) {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

(NumOperands == 5) is already guaranteed here.

++NumErrors;
DivFound = false;
} else if (OperatorProcessing && (NextChar == '-')) {
} else if (OperatorProcessing) {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

so this nested check is redundant and can be removed.

state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(5).Number = Token(Pos + 5).Number;
state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(5).Expression = Token(Pos + 5).Expression;
state.dataRuntimeLang->ErlExpression(ExpressionNum).Operand(5).Variable = Token(Pos + 5).Variable;
if ((NumOperands == 5) && (NumTokens - 6 > 0)) { // too many tokens for this non-binary operator
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

so this nested check is redundant and can be removed.

// Need to make sure that flows are greater than zero
if (MassFlowSet >= 0.0) {
state.dataLoopNodes->Node(NodeNumOut).MassFlowRateSetPoint = MassFlowSet;
} else if (MassFlowSet < 0.0) {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This is redundant since it is the exact opposite of the preceding if (MassFlowSet >= 0.0) in two lines above.


if (ErrorsFound) {
ShowFatalError(state, EnergyPlus::format("{}Errors found in input. Preceding condition(s) cause termination.", RoutineName));
}
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

ErrorsFound is initialized to false and never updated in this routine, so the final fatal check is unreachable.

OASysEqSizing(state.dataSize->CurOASysNum).AirFlow = true;
OASysEqSizing(state.dataSize->CurOASysNum).AirVolFlow = finalSysSizing.DesOutAirVolFlow;
state.dataSize->OASysEqSizing(state.dataSize->CurOASysNum).AirFlow = true;
state.dataSize->OASysEqSizing(state.dataSize->CurOASysNum).AirVolFlow = finalSysSizing.DesOutAirVolFlow;
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Removed the one-use OASysEqSizing alias and used the element directly. This clears the constVariableReference warning and keeps the mutating call explicit.

TempAbsPlate * (hConvCoefA2C + hRadCoefA2C);
tempdenom = (hConvCoefC2O + hRadCoefC2O) + (hConvCoefA2C + hRadCoefA2C);
TempOuterCover = tempnom / tempdenom;
} else if (NumCovers == 2) {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

In this NumCovers == 2 branch, the loop index Num can only be 0 or 1. That means once if (Num == 0) is false, Num == 1 is guaranteed, so the else if (Num == 1) can be simplified to a plain else.

A1eqout = Atop + 0.5 * Abot * (Al + Ar + Ah) / (Abot + Atop);
A2eqin = Atop + 0.5 * Abot * (Al + Ar + Ah) / (Abot + Atop);
} else if (Tgap1 < Tgap2) {
} else {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The else if (Tgap1 < Tgap2) is redundant since it is the exact complement of the preceding if (Tgap1 >= Tgap2). This can be simplified to a plain else for the same intended behavior.

Tup = (alpha1 * Tav1 + beta1 * alpha2 * Tav2) / (1.0 - beta1 * beta2);
Tdown = alpha2 * Tav2 + beta2 * Tup;
} else if (Tgap2 >= Tgap1) {
} else {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The else if (Tgap2 >= Tgap1) is redundant since it is the exact complement of the preceding if (Tgap1 > Tgap2). This can be simplified to a plain else for the same intended behavior.

Temp1 = Tav1 - (H01 / H) * (Tup - Tdown);
Temp2 = Tav2 - (H02 / H) * (Tdown - Tup);
} else if (Tgap2 >= Tgap1) {
} else {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The else if (Tgap2 >= Tgap1) is redundant since it is the exact complement of the preceding if (Tgap1 > Tgap2). This can be simplified to a plain else for the same intended behavior.

qv1 = -dens1 * cp1 * speed1 * s1 * L * (Tdown - Tup) / (H * L);
qv2 = -dens2 * cp2 * speed2 * s2 * L * (Tup - Tdown) / (H * L);
} else if (Tgap2 < Tgap1) {
} else {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The else if (Tgap2 < Tgap1) is redundant since it is the exact complement of the preceding if (Tgap2 >= Tgap1). This can be simplified to a plain else for the same intended behavior.

A1eqin = Abot + 0.5 * Atop * (Al + Ar + Ah) / (Abot + Atop);
A1eqout = Atop + 0.5 * Abot * (Al + Ar + Ah) / (Abot + Atop);
} else if (Tgap <= Tenv) {
} else {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The else if (Tgap <= Tenv) is redundant since it is the exact complement of the preceding if (Tgap > Tenv). This can be simplified to a plain else for the same intended behavior.

ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingAirVolFlow = state.dataSize->DataNonZoneNonAirloopValue;
state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingAirFlow = true;
state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingAirVolFlow = state.dataSize->DataNonZoneNonAirloopValue;
}
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Removed the one-use ZoneEqSizing alias and used the element directly. This clears the constVariableReference warning and keeps the mutating call explicit.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@dareumnam here's my thoughts on this.

Never use a class reference:

auto &ZoneEqSizing = state.dataSize->ZoneEqSizing;

and instead use an object reference:

auto &ZoneEqSizing = state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum);

but don't create the reference unless there are more than 2 usages (that's just my personal preference).

So in this case I agree with this change. You could have used the object reference here and that would still be OK because it was used twice. Creating a reference to use it one time just adds more code than is needed.

Your code change here seems fine to me.

LOK = true;
DOK = true;
BOK = true;
}
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

LOK, DOK, and BOK are assigned throughout this routine but never actually checked afterward, so cppcheck looks right here. It seems these calls are being made for their side effects on L.LWP_EL / L.SWP_EL, while the bool return values are currently unused. If the return status is not needed, the locals can probably be removed. Otherwise this may be missing an error check.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't want to add to the effort here but if these locals are not needed then do these 12 functions even need to return a bool? e.g., bool PD_LWP{ .. return PD_LWP}; Maybe the developer used these bools for debugging and never removed them?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DoNotPublish Includes changes that shouldn't be reported in the changelog

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants