Din statiske analysator har markeret en tilstand som altid falsk. Advarslen ser ud som en af disse, afhængigt af dit værktøj:
- SonarQube: "Betingede udtryk, der altid er sande eller falske, kan føre til uopnåelig kode" (RSPEC-2583)
- IntelliJ / Inspectopedia: "Koden analyseres ikke, fordi betingelsen statisk evalueres som falsk"
- Checkmarx / Fortify: "Uopnåelig kode, død gren fundet"
- ESLint: "ingen-konstant-betingelse, uventet konstant betingelse"
- Pylint: "W0125: Brug af en betinget sætning med en konstant værdi"
Alle disse siger det samme: analysatoren har på analysetidspunktet, uden at køre koden, bevist, at en specifik gren af en betinget sætning aldrig kan udføres. Betingelsen, der beskytter den gren, er altid falsk. Alt inden for den gren er død kode.
Denne vejledning dækker årsagen til disse advarsler, hvordan man identificerer hvilken kategori hver advarsel falder ind under, den korrekte løsning for hver kategori, hvornår undertrykkelse er passende, og hvad altid-falske betingelser i ældre COBOL-kode afslører om migreringsomfanget.
Udgåede forretningsregler stadig i din kode
SMART TS XL identificerer EVALUATE-grene, der refererer til produktkoder, statusværdier og kundetyper, der ikke længere findes i produktionsdata.
FÅ MERE AT VIDE…Hvordan statisk analyse registrerer altid-falske betingelser
Moderne statiske analysatorer bruger symbolsk udførelse og dataflowanalyse, ikke simpel mønstermatchning, til at detektere altid-falske betingelser. Analysatoren sporer de mulige værdier for hver variabel på hvert punkt i programmet. Når den når en betinget, evaluerer den, om betingelsen nogensinde kan være sand givet de kendte begrænsninger på variablerne.
Tre primære mekanismer producerer altid falsk detektion:
Symbolsk udførelse. Analysatoren tildeler symbolske værdier til variabler og sporer, hvordan operationer begrænser disse værdier. Hvis variabel x er tildelt 0 på linje 3 og sammenlignet x > 10 på linje 7 uden mellemliggende tildeling er betingelsen beviseligt falsk.
Typesystembegrænsninger. Nogle betingelser er umulige givet variablens type. Sammenligning af en ikke-null objektreference med null efter en ikke-null assertion, eller sammenligning af en enum-værdi med et tilfælde uden for dets definerede sæt.
Boolsk algebraforenkling. Sammensatte betingelser, der forenkler til false uanset variable værdier: (a && !a), (x > 10 && x < 5), (!flag || false).
SonarQubes regel RSPEC-2583 bruger specifikt symbolsk udførelse: den sporer variablernes tilstand gennem kontrolflowgrafen og markerer betingelser, hvor den symbolske tilstand gør betingelsen beviseligt falsk. IntelliJs advarsel om, at "betingelse statisk evalueret som falsk", bruger den samme fremgangsmåde.
De fire grundlæggende årsager
Korrekt løsning af en altid-falsk advarsel afhænger af korrekt identifikation af hvilken af de fire grundlæggende årsager der gælder. Løsningen er forskellig for hver.
Grundårsag 1: Logisk modsigelse
Betingelsen indeholder en logisk umulighed, to underbetingelser, der ikke begge kan være sande samtidigt, eller en sammensat betingelse, der reduceres til false ved hjælp af boolsk algebra.
Java
// Example: mutually exclusive subconditions
int score = getScore();
if (score > 90 && score < 50) { // Always false: no integer is both > 90 and < 50
applyBonus(); // Never executes
}
// Example: boolean tautology negation
boolean active = isActive();
if (active && !active) { // Always false: a && !a = false
sendNotification(); // Never executes
}
// Example: range check already guaranteed
if (value >= 0) {
if (value < 0) { // Always false: already know value >= 0
handleNegative(); // Never executes
}
}
Løsning: Ret logikken. Enten indeholder betingelsen en tastefejl (udvikleren mente det) score > 90 || score < 50) eller grenen skal fjernes. I eksemplet med områdekontrol er den indre if er overflødig og bør slettes.
Grundårsag 2: Akkumulerede ændringer i forretningsregler
Dette er den mest betydningsfulde årsag i langlivede kodebaser. En betingelse, der var gyldig og meningsfuld, da den blev skrevet, er blevet permanent falsk på grund af efterfølgende ændringer i koden omkring den, uden at nogen har fjernet den nu døde gren.
Java
// 2018: processType could be A, B, or C
// 2023: type C was deprecated and removed from the system
// The processType field is now guaranteed to never equal "C"
// but nobody removed the branch that handled it
public void process(String processType) {
if (processType.equals("A")) {
handleTypeA();
} else if (processType.equals("B")) {
handleTypeB();
} else if (processType.equals("C")) { // Always false since 2023
handleTypeC(); // 47 lines of dead business logic
}
}
python
# Python equivalent: accumulated rule changes
def calculate_rate(customer_tier: str) -> float:
if customer_tier == "GOLD":
return 0.05
elif customer_tier == "SILVER":
return 0.03
elif customer_tier == "BRONZE":
# BRONZE tier was eliminated in Q2 2021
# All BRONZE customers were migrated to SILVER
# This branch has been dead for 4+ years
return 0.01 # Never executes
return 0.0
Løsning: Bekræft forretningskonteksten, og fjern derefter den døde gren helt. Forretningsreglen, der muliggjorde betingelsen, er ændret. Koden, der implementerede den, er ikke længere nødvendig. Dokumenter fjernelsen i commit-meddelelsen: "Fjernet BRONZE-satsgren, niveau elimineret i 2. kvartal 2021, alle kunder migreret til SILVER."
Grundårsag 3: Defensiv programmering til fremtidssikring
Nogle altid-falske betingelser er tilsigtede. Udvikleren skrev dem vel vidende at betingelsen ikke i øjeblikket kan være sand, som en defensiv beskyttelse mod fremtidige kodeændringer, der kan gøre dem sande.
Java
// SonarQube RSPEC-2583 explicitly exempts these:
final boolean DEBUG_MODE = false;
if (DEBUG_MODE) { // Always false -- intentional
dumpDiagnostics(); // Not unreachable in intent, only in fact
}
// Type narrowing that appears redundant
String value = getValue();
if (value == null || value.isEmpty()) {
return;
}
// At this point, static analysis knows value is non-null and non-empty
if (value == null) { // Always false -- already checked above
throw new IllegalStateException(); // Defensive guard
}
SonarQube RSPEC-2583 udskiller eksplicit en undtagelse: "Når betingelsen er en enkelt endelig boolsk værdi" eller "når betingelsen bogstaveligt talt er sand eller falsk", behandles disse som forsætlige og markeres ikke.
Løsning: Hvis betingelsen er et debug-flag eller en kompileringstidskonstant: Lad den være, og tilføj en undertrykkelsesannotation, hvis værktøjet markerer den. Hvis det er en defensiv nul-kontrol eller range guard, der føles overflødig, men er reelt beskyttende: Omstrukturer koden for at gøre beskyttelsen eksplicit på et andet niveau, eller undertryk den med en dokumenteret begrundelse.
Rodårsag 4: Falske positiver fra værktøjskonfigurationen
Statiske analysatorer kan ikke se runtime-konfiguration, miljøvariabler, refleksion, annotationsbehandling eller afhængighedsinjektion. Kode, der vises som altid-falsk for analysatoren, kan muligvis nås via en runtime-mekanisme, som analysatoren ikke kan modellere.
Java
// IntelliJ / Inspectopedia note: "This may cause false-positives if any kind
// of code postprocessing is used, for example, if an annotation processor
// later replaces the method body with something useful."
@ConditionalOnProperty(name = "feature.experimental", havingValue = "true")
public class ExperimentalFeature {
// This class may appear unreachable if the property is false in the
// test configuration the analyzer uses -- but it IS reachable in prod
}
// Method contract that the analyzer cannot see
void run() {
performAction();
System.out.println("Done"); // IntelliJ flags as unreachable
}
@Contract("-> _") // Tells the analyzer: method does NOT always throw
static void performAction() { throw new AssertionError(); }
Løsning: Tilføj den relevante metodekontraktannotation (@Contract til IntelliJ, @NotNull/@Nullable For Kotlin, skriv assertions for TypeScript) for at give analysatoren de nødvendige runtime-oplysninger. Hvis annotationsbaseret opløsning ikke er tilgængelig, skal du bruge værktøjets undertrykkelsesmekanisme med en dokumenteret begrundelse.
COBOL: Hvor altid-falske betingelser afslører årtiers død logik
I COBOL og ældre mainframe-systemer har altid-falske betingelser en anden karakter end i moderne applikationskode og en anden betydning for de teams, der vedligeholder eller moderniserer dem.
COBOL-programmer refaktoreres ikke på samme måde som moderne kode. Når en forretningsregel ændres, en skattekode revideres, et produktniveau fjernes, et regulatorisk krav opdateres, er den almindelige praksis at tilføje den nye logik uden at fjerne den gamle. Den gamle EVALUATE WHEN- eller IF-gren forbliver i kildekoden, beskyttet af en betingelse, der aldrig kan være sand i betragtning af den aktuelle tilstand af de data, den behandler.
COBOL
EVALUATE WS-PRODUCT-TYPE
WHEN 'STD'
PERFORM CALC-STANDARD-RATE
WHEN 'PRM'
PERFORM CALC-PREMIUM-RATE
WHEN 'BAS'
* BAS product type retired June 2009
* All BAS customers converted to STD
* This branch has been dead for 15+ years
PERFORM CALC-BASIC-RATE
WHEN 'LEG'
* LEG (legacy) type eliminated in 2001 system migration
* Should have been removed but was left as "just in case"
PERFORM CALC-LEGACY-RATE
WHEN OTHER
PERFORM HANDLE-UNKNOWN-TYPE
END-EVALUATE.
De to døde grene i denne VURDERING, BAS og LEG, er ikke fejl. De er historiske artefakter: forretningsregler, der var gyldige på bestemte tidspunkter i systemets historie og blev permanent utilgængelige, da disse produkttyper blev udfaset. Ingen fjernede dem, fordi ingen var sikre på, om de stadig var nødvendige, og omkostningerne ved at tage fejl syntes højere end omkostningerne ved at lade dem være på plads.
Hvad altid-falske betingelser i COBOL afslører:
De døde grene repræsenterer forretningslogik, der ikke længere gælder. PERFORM CALC-BASIC-RATE og PERFORM CALC-LEGACY-RATE Mål kan i sig selv være hele afsnit eller sektioner af COBOL-kode, potentielt hundredvis af linjer hver, der ligeledes er døde. Betingelsen "always-false" er indgangspunktet til et træ af død kode, der udbredes gennem PERFORM-relationer.
I et COBOL-program med 100,000 linjer kan døde grene fra udgåede forretningsregler udgøre 20-35 % af den samlede kode. Denne procentdel er migreringsomfang, der ikke behøver at blive konverteret, testet eller valideret i et moderniseringsprogram. Identificering af det før migreringsplanlægning resulterer i en direkte omfangsreduktion, og omfangsreduktion i planlægningsfasen er den mest værdifulde anvendelse af altid-falsk betingelsesanalyse.
Beslutningstræet for resolutionen
Always-false condition warning received
│
▼
Is this a compile-time constant
or debug flag? (DEBUG = false, etc.)
│
Yes ───┼─── No
│ │
Intentional. ▼
Suppress or Does the condition
leave as-is. contain a logic error?
(a > 10 && a < 5, etc.)
│
Yes ───┼─── No
│ │
Fix the Has the condition
logic bug. become false due to
a past business rule
change?
│
Yes ───┼─── No
│ │
Verify, Could a runtime
then remove mechanism make
the dead it reachable?
branch. │
Yes ──── No
│
Add contract
annotation. Remove the
dead branch.
Undertrykkelse: Hvornår og hvordan
Undertrykkelse er passende, når betingelsen er oprigtigt tilsigtet, og værktøjet ikke kan få adgang til kontraktoplysningerne for at forstå hvorfor. Undertrykkelse er ikke passende som en genvej for at undgå at undersøge, hvad advarslen rent faktisk betyder.
Java (SonarQube):
Java
@SuppressWarnings("java:S2583")
if (DEBUG_MODE) { // Intentional: compile-time debug flag
dumpState();
}
Java (IntelliJ):
Java
//noinspection ConstantConditions
if (possiblyNull != null) { // Analyzer cannot see the runtime injection
process(possiblyNull);
}
Python (Pylint):
python
if False: # pylint: disable=W0125
# Intentional: placeholder for future implementation
pass
C# (SonarQube):
csharp
#pragma warning disable S2589
if (IsDebugBuild) { // Compile-time constant -- intentional
LogDiagnostics();
}
#pragma warning restore S2589
COBOL (SMART TS XL / brugerdefineret undertrykkelseskommentar):
COBOL
*>> SUPPRESS UNREACHABLE: BAS branch retained for audit trail
WHEN 'BAS'
PERFORM CALC-BASIC-RATE
Undertrykkelsesdisciplin: Enhver undertrykkelse bør ledsages af en kommentar, der forklarer, hvorfor betingelsen er tilsigtet, ikke blot at den undertrykkes. En undertrykkelseskommentar, der siger
// suppress unreachableer værre end ingen undertrykkelse, det skjuler advarslen uden at forklare, hvorfor advarslen er forkert. En undertrykkelse, der siger// suppress: DEBUG_MODE is a compile-time constant, branch is retained for IDE visibilityer acceptabel.
Hvordan SMART TS XL Identificerer altid-falske betingelser på porteføljeskala
SMART TS XL's statisk kodeanalyse anvender dataflow- og kontrolflowanalyse på tværs af COBOL, JCL, Java, Python og alle andre sprog i miljøet for at identificere betingelser, der statisk kan bevises som altid-falske, på porteføljeniveau, på tværs af tusindvis af programmer samtidigt, ikke én fil ad gangen i et udvikler-IDE.
For COBOL-porteføljer betyder dette specifikt: hver EVALUATE WHEN-klausul og hver IF-betingelse i hvert program analyseres i forhold til de kendte begrænsninger på de data, der flyder ind i den. Betingelser, der refererer til produktkoder, statusflag eller typekoder, hvis gyldige værdisæt har ændret sig i løbet af programmets historik, markeres som potentielle døde grene. Outputtet er en oversigt over død kode: hvert program, hver død gren og det estimerede antal linjer af død kode, der kan nås fra hver altid-falsk-betingelse.
Analysen af den ældre modernisering konverterer denne inventarbeholdning til en reduktion af omfanget: hver død gren udelukkes fra migreringsspecifikationen, før en konverteringsindsats påbegyndes. Et program, der tilsyneladende har 2,000 linjer forretningslogik, kan have 600 linjer død forretningslogik fra udgåede produkttyper, eliminerede kundeniveauer og forældede beregningsstier. Migrering af 1,400 linjer i stedet for 2,000 linjer er en reduktion på 30 % af omfanget for det pågældende program, og de døde grene er den del af omfanget, der har den højeste risiko at migrere, fordi ingen ved, hvad de skulle gøre i første omgang.
Virksomhedssøgningsfunktionen gør det muligt at forespørge på den altid-falske opgørelse: find alle COBOL-programmer, der indeholder en EVALUATE WHEN-klausul, der refererer til en produktkode , der ikke er i det aktuelle produktkatalog, alle programmer, der kontrollerer for en statusflagværdi, der ikke har eksisteret i databasen siden et bestemt år, og alle IF-betingelser, der refererer til et datastrukturfelt, der er blevet genbrugt, siden betingelsen blev skrevet. Disse forespørgsler producerer den målrettede opgørelse over døde koder, som manuel kodegennemgang ville tage måneder at producere på tværs af en stor COBOL-portefølje.
Advarslen er normalt korrekt
Advarsler om statisk analyse for altid-falske betingelser er i de fleste tilfælde nøjagtige fund. Betingelsen er altid falsk. Grenen udføres aldrig. Koden i den er død.
Den passende reaktion er ikke undertrykkelse, men undersøgelse. Hvilken grundlæggende årsag gælder? Logisk modsigelse, akkumuleret ændring af forretningsregler, bevidst defensiv programmering eller falsk positiv værktøjsudløsning fra runtime-konfigurationen? Hver af dem har en korrekt løsning. Tre af de fire resulterer i fjernelse af den døde kode. Én resulterer i undertrykkelse med begrundelse.
For ældre COBOL-systemer er altid-falsk-tilstandsanalyse på porteføljeniveau ikke primært en øvelse i kodekvalitet, men en øvelse i at reducere omfanget. De døde grene, der akkumuleres over årtiers ændringer i forretningsregler, repræsenterer en migreringsindsats, der ikke bør foretages. At finde dem, før migreringsplanen låses, er den mest værdifulde anvendelse af altid-falsk-tilstandsanalyse for ethvert team, der planlægger et COBOL-moderniseringsprogram.
Analysatoren fortæller dig noget sandt. Lyt til det.


