All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.plugins.python.api.cfg.ControlFlowGraph Maven / Gradle / Ivy

There is a newer version: 4.26.0.19456
Show newest version
/*
 * SonarQube Python Plugin
 * Copyright (C) 2011-2024 SonarSource SA
 * mailto:info AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the Sonar Source-Available License for more details.
 *
 * You should have received a copy of the Sonar Source-Available License
 * along with this program; if not, see https://sonarsource.com/license/ssal/
 */
package org.sonar.plugins.python.api.cfg;

import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.function.Function;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.plugins.python.api.PythonFile;
import org.sonar.plugins.python.api.tree.FileInput;
import org.sonar.plugins.python.api.tree.FunctionDef;
import org.sonar.plugins.python.api.tree.StatementList;
import org.sonar.plugins.python.api.tree.Tree;
import org.sonar.python.cfg.ControlFlowGraphBuilder;

public class ControlFlowGraph {

  private static final Logger LOG = LoggerFactory.getLogger(ControlFlowGraph.class);

  private final Set blocks;
  private final CfgBlock start;
  private final CfgBlock end;

  // we shouldn't prevent trees from being garbage collected
  private static Set treesWithCfgErrors = Collections.newSetFromMap(new WeakHashMap<>());

  public ControlFlowGraph(Set blocks, CfgBlock start, CfgBlock end) {
    this.blocks = blocks;
    this.start = start;
    this.end = end;
  }

  @CheckForNull
  private static ControlFlowGraph build(@Nullable StatementList statementList, PythonFile file) {
    if (!treesWithCfgErrors.contains(statementList)) {
      try {
        return new ControlFlowGraphBuilder(statementList).getCfg();
      } catch (Exception e) {
        treesWithCfgErrors.add(statementList);
        LOG.warn("Failed to build control flow graph in file [{}]: {}", file, e.getMessage());
      }
    }
    return null;
  }

  @CheckForNull
  public static ControlFlowGraph build(FunctionDef functionDef, PythonFile file) {
    return build(functionDef.body(), file);
  }

  @CheckForNull
  public static ControlFlowGraph build(FileInput fileInput, PythonFile file) {
    return build(fileInput.statements(), file);
  }

  public CfgBlock start() {
    return start;
  }

  public CfgBlock end() {
    return end;
  }

  public Set blocks() {
    return blocks;
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();

    Function, List> sortedByDisplayString = list -> list.stream()
      .sorted(Comparator.comparing(Object::toString))
      .toList();

    List sortedBlocks = sortedByDisplayString.apply(blocks);
    int graphNodeId = 0;
    Map graphNodeIds = new HashMap<>();
    for (CfgBlock block : sortedBlocks) {
      graphNodeIds.put(block, graphNodeId);
      sb.append(graphNodeId).append("[label=\"").append(block.toString()).append("\"];");
      graphNodeId++;
    }
    for (CfgBlock block : sortedBlocks) {
      int id = graphNodeIds.get(block);
      for (CfgBlock successor : sortedByDisplayString.apply(block.successors())) {
        sb.append(id).append("->").append(graphNodeIds.get(successor)).append(";");
      }
      if (block.syntacticSuccessor() != null) {
        sb.append(id).append("->").append(graphNodeIds.get(block.syntacticSuccessor())).append("[style=dotted];");
      }
    }
    return sb.toString();
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy