Дипломная работа: Оценка возможностей применения инструментов статического анализа в учебном процессе для проверки решений задач по программированию

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Приложение 1

ЛистингSQL-скриптов задания структур данных

CREATEGENERATORBEAR_GEN;

CREATE TABLE BEAR (

ID_BEAR INTEGER NOT NULL,

NAME VARCHAR(50) NOT NULL

);

ALTER TABLE BEAR ADD PRIMARY KEY (ID_BEAR);

SET TERM ;

CREATE OR ALTER TRIGGER SET_BEAR_ID FOR BEAR

ACTIVE BEFORE INSERT POSITION 0

AS

BEGIN

new.ID_BEAR = gen_id(BEAR_GEN, 1);

END

SET TERM ;

CREATE TABLE COMPIL_BEAR (

ID_BEAR INTEGER NOT NULL,

ID_CMP INTEGER NOT NULL,

ENABLED CHAR(1) DEFAULT 'y' NOT NULL,

SHOWED CHAR(1) DEFAULT 'y' NOT NULL

);

ALTER TABLE COMPIL_BEAR ADD PRIMARY KEY (ID_BEAR, ID_CMP);

ALTER TABLE COMPIL_BEAR ADD FOREIGN KEY (ID_BEAR) REFERENCES BEAR (ID_BEAR);

ALTER TABLE COMPIL_BEAR ADD FOREIGN KEY (ID_CMP) REFERENCES COMPIL (ID_CMP);

CREATE GENERATOR SOLUTION_ISSUE_GEN;

CREATE TABLE SOLUTION_ISSUE (

ISSUE_ID INTEGER NOT NULL,

ID_STAT INTEGER NOT NULL,

START_LINE INTEGER,

START_COL INTEGER,

END_LINE INTEGER,

END_COL INTEGER,

MESSAGE VARCHAR(1000) NOT NULL,

ID_BEAR INTEGER NOT NULL,

SEVERITY INTEGER NOT NULL

);

ALTER TABLE SOLUTION_ISSUE ADD PRIMARY KEY (ISSUE_ID);

ALTER TABLE SOLUTION_ISSUE ADD FOREIGN KEY (ID_STAT) REFERENCES STATUS (ID_STAT);

ALTER TABLE SOLUTION_ISSUE ADD FOREIGN KEY (ID_BEAR) REFERENCES BEAR (ID_BEAR);

SET TERM ;

CREATE OR ALTER TRIGGER SET_ISSUE_ID FOR SOLUTION_ISSUE

ACTIVE BEFORE INSERT POSITION 0

AS

BEGIN

new.ISSUE_ID = gen_id(SOLUTION_ISSUE_GEN, 1);

END

SET TERM ;

Приложение 2

Листинг конфигурации сборки проекта Gradle

plugins {

id 'war'

id 'org.springframework.boot' version '2.1.5.RELEASE'

}

apply plugin: 'io.spring.dependency-management'

group 'ru.edu.vstu.atpp'

version '1.0-SNAPSHOT'

sourceCompatibility = 1.8

repositories {

mavenCentral()

}

dependencies {

implementation "org.springframework.boot:spring-boot-starter-amqp"

implementation 'org.springframework.boot:spring-boot-starter-web'

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

implementation 'org.springframework.boot:spring-boot-starter-security'

implementation 'org.springframework.boot:spring-boot-starter-test'

implementation group: 'org.firebirdsql.jdbc', name: 'jaybird-jdk18', version: '3.0.6'

implementation group: 'org.apache.commons', name: 'commons-exec', version: '1.3'

implementation group: 'commons-io', name: 'commons-io', version: '2.6'

implementation 'com.google.guava:guava:28.0-jre'

testCompile group: 'junit', name: 'junit', version: '4.12'

}

Приложение 3

Листинг сгенерированной JPA-сущности ошибки статического анализа

@Entity

@Table(name = "SOLUTION_ISSUE", schema = "", catalog = "")

public class SolutionIssueEntity {

private int issueId;

private Integer startLine;

private Integer startCol;

private Integer endLine;

private Integer endCol;

private String message;

private int severity;

private StatusEntity statusByIdStat;

private BearEntity bearByIdBear;

@Id

@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "issueIdGen")

@GenericGenerator(name = "issueIdGen", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",

parameters = {@org.hibernate.annotations.Parameter(name = "sequence_name", value = "SOLUTION_ISSUE_GEN")

})

@Column(name = "ISSUE_ID")

public int getIssueId() {

return issueId;

}

public void setIssueId(int issueId) {

this.issueId = issueId;

}

@Basic

@Column(name = "START_LINE")

public Integer getStartLine() {

return startLine;

}

public void setStartLine(Integer startLine) {

this.startLine = startLine;

}

@Basic

@Column(name = "START_COL")

public Integer getStartCol() {

return startCol;

}

public void setStartCol(Integer startCol) {

this.startCol = startCol;

}

@Basic

@Column(name = "END_LINE")

public Integer getEndLine() {

return endLine;

}

public void setEndLine(Integer endLine) {

this.endLine = endLine;

}

@Basic

@Column(name = "END_COL")

public Integer getEndCol() {

return endCol;

}

public void setEndCol(Integer endCol) {

this.endCol = endCol;

}

@Basic

@Column(name = "MESSAGE")

public String getMessage() {

return message;

}

public void setMessage(String message) {

this.message = message;

}

@Basic

@Column(name = "SEVERITY")

public int getSeverity() {

return severity;

}

public void setSeverity(int severity) {

this.severity = severity;

}

@Override

public boolean equals(Object o) {

if (this == o) return true;

if (o == null || getClass() != o.getClass()) return false;

SolutionIssueEntity that = (SolutionIssueEntity) o;

return issueId == that.issueId &&

severity == that.severity &&

Objects.equals(startLine, that.startLine) &&

Objects.equals(startCol, that.startCol) &&

Objects.equals(endLine, that.endLine) &&

Objects.equals(endCol, that.endCol) &&

Objects.equals(message, that.message);

}

@Override

public int hashCode() {

return Objects.hash(issueId, startLine, startCol, endLine, endCol, message, severity);

}

@ManyToOne

@JoinColumn(name = "ID_STAT", referencedColumnName = "ID_STAT", nullable = false)

public StatusEntity getStatusByIdStat() {

return statusByIdStat;

}

public void setStatusByIdStat(StatusEntity statusByIdStat) {

this.statusByIdStat = statusByIdStat;

}

@ManyToOne

@JoinColumn(name = "ID_BEAR", referencedColumnName = "ID_BEAR", nullable = false)

public BearEntity getBearByIdBear() {

return bearByIdBear;

}

public void setBearByIdBear(BearEntity bearByIdBear) {

this.bearByIdBear = bearByIdBear;

}

}

Приложение 4

Листинг слушателя сообщений от AMQP-брокера

@Component

public class CheckingCompletionListener {

public static final Logger LOGGER = LoggerFactory.getLogger(CheckingCompletionListener.class);

private StatusRepository statusRepository;

private Analyzer analyzer;

@Autowired

public CheckingCompletionListener(StatusRepository statusRepository, Analyzer analyzer) {

this.statusRepository = statusRepository;

this.analyzer = analyzer;

}

@RabbitListener(queues = "accepted_solutions")

@Transactional

public void processMessage(String content) throws IOException {

Properties properties = new Properties();

properties.load(new StringReader(content));

Integer solutionId = Integer.valueOf(properties.getProperty("id_stat"));

StatusEntity status = statusRepository.findById(solutionId).get();

if (status.getResultsByIdRsl().getIdRsl() != 0) {

LOGGER.info("Решение {} непрошлопроверку. Пропуск статического анализа", solutionId);

return;

}

Map<String, BearEntity> bears = status.getCompilByIdCmp().getCompilBearsByIdCmp().stream()

.filter(CompilBearEntity::isEnabled)

.map(CompilBearEntity::getBearByIdBear)

.collect(Collectors.toMap(BearEntity::getName, bear -> bear));

if (bears.isEmpty()) {

LOGGER.info("Нет доступных модулей проверки. Пропуск проверки. Решение {}", solutionId);

return;

}

List<Issue> issues = analyzer.analyze(new String(status.getObjData()), bears.keySet());

if (issues.isEmpty()) {

LOGGER.info("Проблемы не обнаружены. Решение {}", solutionId);

return;

}

List<SolutionIssueEntity> issueEntities = issues.stream().map(issue -> {

SolutionIssueEntity issueEntity = new SolutionIssueEntity();

issueEntity.setMessage(issue.getMessage());

issueEntity.setStartLine(issue.getStartLine());

issueEntity.setStartCol(issue.getStartCol());

issueEntity.setEndLine(issue.getEndLine());

issueEntity.setEndCol(issue.getEndCol());

issueEntity.setBearByIdBear(bears.entrySet().stream()

.filter(entry -> issue.getBear().contains(entry.getKey())).findAny().get().getValue());

issueEntity.setStatusByIdStat(status);

issueEntity.setSeverity(issue.getSeverity());

return issueEntity;

}).collect(Collectors.toList());

status.setSolutionIssuesByIdStat(issueEntities);

LOGGER.info("Найдено {} проблем. Решение {}", issues.size(), solutionId);

}

}

Приложение 5

Листинги REST-контроллеров

1 Листинг REST-контроллера для пользователей с ролью USER

@RestController

public class UserController {

private IssueMapper issueMapper;

private StatusRepository statusRepository;

@Autowired

public UserController(IssueMapper issueMapper, StatusRepository statusRepository) {

this.issueMapper = issueMapper;

this.statusRepository = statusRepository;

}

@GetMapping("/issues")

@Transactional

public List<Issue> getIssues(@RequestParam("stat_id") Integer statId) {

List<SolutionIssueEntity> issueEntities = statusRepository.findById(statId).get()

.getSolutionIssuesByIdStat().stream().filter(issue ->

issue.getStatusByIdStat().getCompilByIdCmp().getCompilBearsByIdCmp().stream().anyMatch(compilBear ->

compilBear.isShowed() && compilBear.getBearByIdBear() == issue.getBearByIdBear()

)

).sorted((o1, o2) -> o2.getSeverity() - o1.getSeverity()).collect(Collectors.toList());

return issueMapper.convert(issueEntities);

}

}

2 ЛистингREST-контроллерадляпользователейсрольюADMIN

@RestController

@RequestMapping("/admin")

public class AdminController {

private CompilRepository compilRepository;

private CompilBearRepository compilBearRepository;

@Autowired

public AdminController(CompilRepository compilRepository, CompilBearRepository compilBearRepository) {

this.compilRepository = compilRepository;

this.compilBearRepository = compilBearRepository;

}

@GetMapping("/bears")

public List<Compiler> getBears() {

Iterable<CompilEntity> compilers = compilRepository.findAll();

return StreamSupport.stream(compilers.spliterator(), false)

.map(compiler -> new Compiler(compiler.getIdCmp(), compiler.getName().trim(), compiler.getCompilBearsByIdCmp().stream().map(

bear -> new BearStatus(bear.getBearByIdBear().getIdBear(),

bear.getBearByIdBear().getName(),

bear.isEnabled(),

bear.isShowed())).collect(Collectors.toList()))).collect(Collectors.toList());

}

@PostMapping("/analysis-state")

@Transactional

public void analysisState(@RequestParam("compiler_id") Integer compilerId, @RequestParam("bear_id") Integer bearId, @RequestParam("enabled") Boolean enabled) {

compilBearRepository.setEnabled(enabled, compilerId.shortValue(), bearId);

}

@PostMapping("/showing-state")

@Transactional

public void showingState(@RequestParam("compiler_id") Integer compilerId, @RequestParam("bear_id") Integer bearId, @RequestParam("enabled") Boolean enabled) {

compilBearRepository.setShowed(enabled, compilerId.shortValue(), bearId);

}

}

Приложение 6

Листинг конфигурации контекста безопасности приложения

@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter {

private DataSource dataSource;

@Autowired

public SecurityConfig(DataSource dataSource) {

this.dataSource = dataSource;

}

@Override

protected void configure(HttpSecurity http) throws Exception {

http.authorizeRequests()

.antMatchers("/admin/**").hasAuthority("ADMIN")

.antMatchers("/**").hasAnyAuthority("USER", "ADMIN")

.and().httpBasic()

.and().csrf().disable();

}

@Override

protected void configure(AuthenticationManagerBuilder auth) throws Exception {

auth.jdbcAuthentication().dataSource(dataSource)

.usersByUsernameQuery("select rtrim(login), rtrim(pwd), 1 from authors where login=?")

.authoritiesByUsernameQuery("select rtrim(login), rtrim(case sec" +

" when 1 then 'MASTER' when 2 then 'ADMIN' else 'USER' end)" +

" from authors left join author_sec" +

" on authors.id_publ=author_sec.id_publ" +

" where login=?")

.passwordEncoder(NoOpPasswordEncoder.getInstance());

}

}

Приложение 7

Листинг JavaScript-программы, управляющей списком ошибок на странице просмотра

ts(['$color_lang']);

var issues_loaded = false;

var originalCode;

var highlightedCode;

var currentCode;

var issues;

function googleSectionalElementInit() {

new google.translate.SectionalElement({

sectionalNodeClassName: 'goog-trans-section',

controlNodeClassName: 'goog-trans-control',

background: 'trasparent'

}, 'google_sectional_element');

}

$( function() {

originalCode = $(".$color_lang");

initHighlighting.apply(null, ['$color_lang']);

currentCode = highlightedCode = $(".$color_lang");

$( "#accordion" ).accordion({

collapsible: true,

active: false,

heightStyle: "content",

activate: function (e, ui) {

if(ui.newHeader.length>0){

if(!issues_loaded==1){

$.getJSON("/sas/issues?stat_id=$id_stat", function(data) {

issues = data;

var items = [];

$.each( data, function( key, val ) {

items.push( "<a href='#' id='issue-" + key + "' class='issue-text'>" + val.message + "</a><br/>" );

});

$(ui.newHeader[0]).next().html(items.join( "" ));

issues_loaded=true;

});

}

} else {

currentCode.replaceWith(highlightedCode);

currentCode = highlightedCode;

}

}

});

$('#accordion').on('click', 'a', function(event){

var issue = issues[event.target.id.substr(6)];

var code = originalCode.clone();

var content = code.html();

var startIndex = 0;

var i = 0;

while (i < issue.startLine) {

var eolIndex = content.indexOf('\n', startIndex);

if (eolIndex == -1) {

startIndex = content.length;

break;

}

startIndex = eolIndex + 1;

i++;

}

if (issue.startCol != null) {

startIndex += issue.startCol;

}

var endIndex = 0;

i = 0;

while (i < issue.endLine) {

var eolIndex = content.indexOf('\n', endIndex);

if (eolIndex == -1) {

break;

}

endIndex = eolIndex + 1;

i++;

}

if (issue.endCol != null) {

endIndex += issue.endCol;

} else {

endIndex = content.indexOf('\n', endIndex);

if (endIndex == -1) {

endIndex = content.length;

}

}

var contentBeforeHighlightText = content.substr(0, startIndex);

var contentAfterHighlightText = content.substr(endIndex + 1);

var highlightedText = "<span class=\"highlight-issue\">" + content.substring(startIndex, endIndex + 1) + "</span>";

content = contentBeforeHighlightText + highlightedText + contentAfterHighlightText;

code.html(content);

currentCode.replaceWith(code);

currentCode = code;

});

});

Приложение 8

Листинг JavaScript-программы, управляющей панелью администрирования модулей статического анализа

$( function() {

var compilers;

$.getJSON("/sas/admin/bears", function(data) {

compilers = data;

var items = [];

items.push("<table border=\"1\"><tr><td>Compiler</td><td>Checkers</td></tr>");

$.each( compilers, function( key, compiler ) {

items.push( "<tr><td><p>" + compiler.compilerName + "</td><td><input type=\"button\" class=\"compiler\" id=\"compiler-" + compiler.id + "\" value=\"Show\"/>");

items.push("<div style=\"display:none\" id=\"bears-" + compiler.id + "\"><table border=\"1\"><tr><td>Checker</td><td>Enabled</td><td>Showed</td></tr>");

$.each( compiler.bears, function( key, bear ) {

items.push("<tr><td>" + bear.bearName + "</td><td><input type=\"checkbox\" class=\"enabled\" id=\"enabled-" + compiler.id + "-" + bear.id + "\" value=\"Enabled\"" + (bear.enabled ? " checked" : "") + "/>");

items.push("<td><input type=\"checkbox\" class=\"showed\" id=\"showed-" + compiler.id + "-" + bear.id + "\" value=\"Showed\"" + (bear.showed ? " checked" : "") + "/></tr>");

});

items.push("</table></div></td></tr>")

});

items.push("</table>");

$("#static-analysis").html(items.join( "" ));

});

$("#static-analysis").on("click", ".compiler", function(event){

if (event.target.value == "Show") {

$("#bears-" + event.target.id.substr(9)).show();

event.target.value = "Hide";

} else {

$("#bears-" + event.target.id.substr(9)).hide();

event.target.value = "Show";

}

});

$("#static-analysis").on("change", ".enabled", function(event){

var substr = event.target.id.substr(8);

var delimiterIndex = substr.indexOf("-");

$.post("/sas/admin/analysis-state?compiler_id=" + substr.substring(0, delimiterIndex) + "&bear_id=" + substr.substr(delimiterIndex + 1) + "&enabled=" + event.target.checked);

});

$("#static-analysis").on("change", ".showed", function(event){

var substr = event.target.id.substr(7);

var delimiterIndex = substr.indexOf("-");

$.post("/sas/admin/showing-state?compiler_id=" + substr.substring(0, delimiterIndex) + "&bear_id=" + substr.substr(delimiterIndex + 1) + "&enabled=" + event.target.checked);

});

});

Приложение 9

Пример обнаруживаемых ошибок

Исходный текст программы на Java:

public class IntArrayList {

int[] arrInt;

int size;

static final int MAX_VALUE = 2147483647;

IntArrayList() {

this.arrInt = new int[500];

this.size = 0;

}

public IntArrayList(int initialCapacity) {

try {

this.arrInt = new int[initialCapacity];

this.size = 0;

} catch (IllegalArgumentException e) {

e.printStackTrace();

}

}

public boolean add(int value) {

try {

if (this.isFull()) {

arrInt = copyToArray();

}

arrInt[size] = value;

size++;

return true;

} catch (IllegalArgumentException e) {

e.printStackTrace();

}

throw new IllegalArgumentException();

}

public void add(int index, int value) {

if (size >= index && index >= 0) {

if (size == index) {

try {

if (this.isFull()) {

arrInt = copyToArray();

}

arrInt[size] = value;

size++;

return;

} catch (IllegalArgumentException e) {

e.printStackTrace();

}

}

try {

if (this.isFull()) {

arrInt = copyToArray();

}

offset(index);

arrInt[index] = value;

size++;

} catch (IllegalArgumentException e) {

e.printStackTrace();

}

} else throw new IndexOutOfBoundsException();

}

public int get(int index) {

if (size > index && index >= 0) {

return arrInt[index];

} else throw new IllegalArgumentException();

}

public int set(int index, int value) {

int last = 0;

if (size > index && index >= 0) {

try {

last = arrInt[index];

arrInt[index] = value;

return last;

} catch (IllegalArgumentException e) {

e.printStackTrace();

}

}

throw new IndexOutOfBoundsException();

}

public int size() {

return this.size;

}

public void clear() {

size = 0;

}

private boolean isFull() {

if (size == arrInt.length) {

return true;

}

return false;

}

private int[] copyToArray() {

int[] temp;

if ((double) (MAX_VALUE / arrInt.length) > 1.0) {

temp = new int[arrInt.length * 2];

} else {

temp = new int[arrInt.length + (MAX_VALUE - arrInt.length)];

}

int length = arrInt.length;

for (int i = 0; i < length; i++) {

temp[i] = arrInt[i];

}

return temp;

}

private void offset(int index) {

int length = size - index;

for (int i = 0; i < length; i++) {

arrInt[size - i] = arrInt[size - i - 1];

}

}

}

Рисунок 10 - Результаты статического анализа программы на Java