onPlayerInteract
has a cyclomatic complexity of 17 with "High" risk205 }
206
207 @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) // cancel on low since some plugins check cancels on normal instead of monitor
208 public final void onPlayerInteract(final PlayerInteractEvent e) {209 final Player player = e.getPlayer();
210 if (CombatUtils.isWorldExcluded(player.getWorld().getName()) || e.getAction() != Action.RIGHT_CLICK_BLOCK)
211 return;
onPlaceholderRequest
has a cyclomatic complexity of 18 with "High" risk 36 }
37
38 @Override
39 public String onPlaceholderRequest(final Player player, final String identifier) { 40 if (player == null)
41 return "";
42
disableActions
has a cyclomatic complexity of 16 with "High" risk142 }
143 }
144
145 private void disableActions(final Player attacker, final Player defender, final PvPlayer pvpAttacker, final PvPlayer pvpDefender) {146 final boolean hasExemptPerm = pvpAttacker.hasPerm(Permissions.EXEMPT_DISABLE_ACTIONS);
147 if (Settings.isDisableFly()) {
148 if (CombatUtils.canFly(attacker) && !hasExemptPerm) {
setup
has a cyclomatic complexity of 15 with "Medium" risk 28 setup();
29 }
30
31 private void setup() { 32 if (!combatPrefix.isEmpty() || !combatSuffix.isEmpty()) {
33 if (scoreboard.getTeam(combatTeamID) != null) {
34 inCombat = scoreboard.getTeam(combatTeamID);
debug
has a cyclomatic complexity of 20 with "High" risk160 });
161 }
162
163 private void debug(final CommandSender sender, final String[] args) {164 PvPlayer p = null;
165 if (args.length == 2 && sender instanceof Player) {
166 p = plugin.getPlayerHandler().get((Player) sender);
A function with high cyclomatic complexity can be hard to understand and maintain. Cyclomatic complexity is a software metric that measures the number of independent paths through a function. A higher cyclomatic complexity indicates that the function has more decision points and is more complex.
Functions with high cyclomatic complexity are more likely to have bugs and be harder to test. They may lead to reduced code maintainability and increased development time.
To reduce the cyclomatic complexity of a function, you can:
The method below (from the source code of the Maven build system, non-branch lines have been abbreviated) has a complexity of 25, and should be refactored if possible.
public VersionResult resolveVersion(RepositorySystemSession session, VersionRequest request) // 1
throws VersionResolutionException {
// ...
if (cache != null && !ConfigUtils.getBoolean(session, false, "aether.versionResolver.noCache")) { // +2
// ...
if (obj instanceof Record) { // +1
}
}
Metadata metadata = null;
// This section could be refactored, as all operations here are independent of external control flow.
if (RELEASE.equals(version)) { // +1
metadata = new DefaultMetadata(
artifact.getGroupId(), artifact.getArtifactId(), MAVENMETADATAXML, Metadata.Nature.RELEASE);
} else if (LATEST.equals(version)) { // +1
metadata = new DefaultMetadata(
artifact.getGroupId(),
artifact.getArtifactId(),
MAVENMETADATAXML,
Metadata.Nature.RELEASEORSNAPSHOT);
} else if (version.endsWith(SNAPSHOT)) { // +1
WorkspaceReader workspace = session.getWorkspaceReader();
if (workspace != null && workspace.findVersions(artifact).contains(version)) { // +2
metadata = null;
result.setRepository(workspace.getRepository());
} else {
metadata = new DefaultMetadata(
artifact.getGroupId(),
artifact.getArtifactId(),
version,
MAVENMETADATAXML,
Metadata.Nature.SNAPSHOT);
}
} else {
metadata = null;
}
if (metadata == null) { // +1
result.setVersion(version);
} else {
// ...
for (RemoteRepository repository : request.getRepositories()) { // +1
// ...
}
// ...
for (MetadataResult metadataResult : metadataResults) { // +1
// ...
if (repository == null) { // +1
// ...
}
Versioning v = readVersions(session, trace, metadataResult.getMetadata(), repository, result);
merge(artifact, infos, v, repository);
}
// This section could also be extracted for the same reasons.
if (RELEASE.equals(version)) { // +1
resolve(result, infos, RELEASE);
} else if (LATEST.equals(version)) { // +1
if (!resolve(result, infos, LATEST)) { // +1
resolve(result, infos, RELEASE);
}
if (result.getVersion() != null && result.getVersion().endsWith(SNAPSHOT)) { // +2
VersionRequest subRequest = new VersionRequest();
subRequest.setArtifact(artifact.setVersion(result.getVersion()));
if (result.getRepository() instanceof RemoteRepository) { // +1
RemoteRepository r = (RemoteRepository) result.getRepository();
subRequest.setRepositories(Collections.singletonList(r));
} else {
subRequest.setRepositories(request.getRepositories());
}
VersionResult subResult = resolveVersion(session, subRequest);
result.setVersion(subResult.getVersion());
result.setRepository(subResult.getRepository());
for (Exception exception : subResult.getExceptions()) { // +1
result.addException(exception);
}
}
} else {
String key = SNAPSHOT + getKey(artifact.getClassifier(), artifact.getExtension());
merge(infos, SNAPSHOT, key);
if (!resolve(result, infos, key)) { // +1
result.setVersion(version);
}
}
if (StringUtils.isEmpty(result.getVersion())) { // +1
throw new VersionResolutionException(result);
}
}
if (cacheKey != null && metadata != null && isSafelyCacheable(session, artifact)) { // +3
cache.put(session, cacheKey, new Record(result.getVersion(), result.getRepository()));
}
return result;
}
It is best to refactor the method into multiple separate methods, so that the complexity of individual methods is reduced.
Here, after extracting the parts of the code highlighted above, the complexity is reduced to 12
, and shifted into two other methods instead.
public VersionResult resolveVersion(RepositorySystemSession session, VersionRequest request) // 1
throws VersionResolutionException {
// ...
if (cache != null && !ConfigUtils.getBoolean(session, false, "aether.versionResolver.noCache")) { // +2
// ...
if (obj instanceof Record) { // +1
// ...
}
}
Metadata metadata = getMetadataForVersion(session, version, artifact, result);
if (metadata == null) { // +1
// ...
} else {
// ...
for (RemoteRepository repository : request.getRepositories()) { // +1
// ...
}
// ...
for (MetadataResult metadataResult : metadataResults) { // +1
// ...
if (repository == null) { // +1
// ...
}
// ...
}
resolveBasedOnVersion(session, request, version, result, infos, artifact);
if (StringUtils.isEmpty(result.getVersion())) { // +1
throw new VersionResolutionException(result);
}
}
if (cacheKey != null && metadata != null && isSafelyCacheable(session, artifact)) { // +3
cache.put(session, cacheKey, new Record(result.getVersion(), result.getRepository()));
}
return result;
}
private void resolveBasedOnVersion(RepositorySystemSession session, VersionRequest request, String version, VersionResult result, Map<String, VersionInfo> infos, Artifact artifact) throws VersionResolutionException {
if (RELEASE.equals(version)) { // +1
resolve(result, infos, RELEASE);
} else if (LATEST.equals(version)) { // +1
if (!resolve(result, infos, LATEST)) { // +1
resolve(result, infos, RELEASE);
}
if (result.getVersion() != null && result.getVersion().endsWith(SNAPSHOT)) { // +2
// ...
if (result.getRepository() instanceof RemoteRepository) { // +1
// ...
} else {
// ...
}
// ...
for (Exception exception : subResult.getExceptions()) { // +1
result.addException(exception);
}
}
} else {
// ...
if (!resolve(result, infos, key)) { // +1
result.setVersion(version);
}
}
}
@Nullable
private static Metadata getMetadataForVersion(RepositorySystemSession session, String version, Artifact artifact, VersionResult result) {
if (RELEASE.equals(version)) { // +1
// ...
} else if (LATEST.equals(version)) { // +1
// ...
} else if (version.endsWith(SNAPSHOT)) { // +1
WorkspaceReader workspace = session.getWorkspaceReader();
if (workspace != null && workspace.findVersions(artifact).contains(version)) { // +2
// ...
} else {
// ...
}
} else {
metadata = null;
}
return metadata;
}
Cyclomatic complexity threshold can be configured using the
cyclomatic_complexity_threshold
meta field in your repository's
.deepsource.toml
config file.
Configuring this is optional. If you don't provide a value, the Analyzer will
raise issues for functions with complexity higher than the default threshold,
which is "medium" (which raises issues for complexity > 15
) for the Java Analyzer.
Here's a mapping of risk category to cyclomatic complexity score to help you configure this better:
Risk category | Cyclomatic complexity range | Recommended action |
---|---|---|
low | 1-5 | No action needed. |
medium | 6-15 | Review and monitor. |
high | 16-25 | Review and refactor. It is recommended to add explanatory comments if the function absolutely cannot be changed. |
very-high | 26-50 | Refactor to reduce the complexity. |
critical | >50 | The function must be refactored. Such high complexity can harm testability and readability. |