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

org.conqat.engine.commons.findings.location.TextRegionLocation Maven / Gradle / Ivy

There is a newer version: 2025.1.0-rc2
Show newest version
/*
 * Copyright (c) CQSE GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.conqat.engine.commons.findings.location;

import java.util.Objects;

import org.conqat.lib.commons.assertion.CCSMAssert;
import org.conqat.lib.commons.test.IndexValueClass;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

import io.swagger.v3.oas.annotations.media.Schema;

/**
 * This class denotes a region of text in an element.
 * 

* Context: Due to the way ConQAT deals with text, the class is a little * bit more complex than expected. First, in ConQAT all text is normalized to * use Unix style line endings (regardless of the line endings in the file). * Second, ConQAT may apply filters, i.e. the internal (filtered) text * representation may be different from the (raw) text in the file. * Additionally, a location is best described by character offsets into the * string, while a user typically expects line numbers. Conversion between all * these representations is easy, as long as ConQAT internal representation is * available. Without it, conversion is not possible. *

* Rationale: When findings are reported to a user, the raw offsets * and/or lines should be used, as these are more meaningful (visible in other * editors as well). Also for persisting in a report, the raw positions are * preferred, as the filtered ones depend on the ConQAT configuration, while raw * offsets are independent of filter configuration. When working with findings * within ConQAT, typically the filtered positions are needed, as most * processors also work on the filtered representation. However, in such a case, * the corresponding element is typically available and thus conversion to the * filtered representation is easy. *

* Implementation: The finding (as well as the findings report) only * stores raw positions. While the offsets would be sufficient, we also store * line numbers to be able to provide meaningful user output. Filtered positions * are not stored, but are made available via utility methods in the resource * bundle. All fields are mandatory, i.e., it is not allowed to fill any * position entry with invalid data (contrary to the old CodeRegionLocation, * where -1 could be used to denote missing information). */ @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", defaultImpl = TextRegionLocation.class) @JsonSubTypes(@JsonSubTypes.Type(value = TeamscaleIssueFieldLocation.class, name = "TeamscaleIssueFieldLocation")) @IndexValueClass(containedInBackup = true) // For some reason, the OpenApi generator does not recognize the superclass, // so add it here again @Schema(allOf = ElementLocation.class) public class TextRegionLocation extends ElementLocation { /** * Version used for serialization. */ private static final long serialVersionUID = 1; /** * An unknown offset used to indicate that the line information is to be used to * calculate character offset from. */ public static final int UNKNOWN_TEXT_REGION_OFFSET = -1; /** * The name of the JSON property name for {@link #rawStartOffset}. */ private static final String RAW_START_OFFSET_PROPERTY = "rawStartOffset"; /** * The name of the JSON property name for {@link #rawEndOffset}. */ private static final String RAW_END_OFFSET_PROPERTY = "rawEndOffset"; /** * The name of the JSON property name for {@link #rawStartLine}. */ private static final String RAW_START_LINE_PROPERTY = "rawStartLine"; /** * The name of the JSON property name for {@link #rawEndLine}. */ private static final String RAW_END_LINE_PROPERTY = "rawEndLine"; /** * The absolute start position of the region in the (raw) text (zero based, * inclusive). */ @JsonProperty(RAW_START_OFFSET_PROPERTY) private final int rawStartOffset; /** * The absolute end position in the (raw) text (zero based, inclusive). */ @JsonProperty(RAW_END_OFFSET_PROPERTY) private final int rawEndOffset; /** * The line corresponding to {@link #rawStartOffset} (one-based, inclusive). */ @JsonProperty(RAW_START_LINE_PROPERTY) private final int rawStartLine; /** * The line corresponding to {@link #rawEndOffset} (one-based, inclusive). */ @JsonProperty(RAW_END_LINE_PROPERTY) private final int rawEndLine; public TextRegionLocation(TextRegionLocation location) { super(location.getUniformPath()); rawStartOffset = location.rawStartOffset; rawEndOffset = location.rawEndOffset; rawStartLine = location.rawStartLine; rawEndLine = location.rawEndLine; } /** * Creates a new location in a text-based file. *

* Offsets are 0-based character offsets from the start of the file (in a * normalized file, i.e., "\r\n" has been replaced by "\n"). *

* Line numbers are 1-based (i.e., code in the first line has line number 1). */ @JsonCreator public TextRegionLocation(@JsonProperty(UNIFORM_PATH_PROPERTY) String uniformPath, @JsonProperty(RAW_START_OFFSET_PROPERTY) int rawStartOffset, @JsonProperty(RAW_END_OFFSET_PROPERTY) int rawEndOffset, @JsonProperty(RAW_START_LINE_PROPERTY) int rawStartLine, @JsonProperty(RAW_END_LINE_PROPERTY) int rawEndLine) { super(uniformPath); CCSMAssert.isTrue(rawStartOffset <= rawEndOffset, "Start offset may not be after end offset."); CCSMAssert.isTrue(rawStartLine <= rawEndLine, "Start line may not be after end line."); this.rawStartOffset = rawStartOffset; this.rawEndOffset = rawEndOffset; this.rawStartLine = rawStartLine; this.rawEndLine = rawEndLine; } /** * Returns the absolute start position of the region in the (raw) text (zero * based, inclusive). */ public int getRawStartOffset() { return rawStartOffset; } /** * Returns the absolute end position in the (raw) text (zero based, inclusive). */ public int getRawEndOffset() { return rawEndOffset; } /** * Returns the line corresponding to {@link #getRawStartOffset()} (one-based, * inclusive). */ public int getRawStartLine() { return rawStartLine; } /** * Returns the line corresponding to {@link #getRawEndOffset()} (one-based, * inclusive). */ public int getRawEndLine() { return rawEndLine; } /** * {@inheritDoc} *

* This includes the start and end line which is typically sufficient for * debugging and showing to a user. */ @Override public String toLocationString() { return super.toLocationString() + ElementLocation.INTERNAL_PATH_SEPARATOR + rawStartLine + "-" + rawEndLine; } @Override public String getLocationKey() { return toLocationString() + " (offsets: " + rawStartOffset + "-" + rawEndOffset + ")"; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } TextRegionLocation that = (TextRegionLocation) o; return super.equals(that) && rawStartOffset == that.rawStartOffset && rawEndOffset == that.rawEndOffset && rawStartLine == that.rawStartLine && rawEndLine == that.rawEndLine; } @Override public int hashCode() { return super.hashCode() * 13 + Objects.hash(rawStartOffset, rawEndOffset, rawStartLine, rawEndLine); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy