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

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

The 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.io.Serial;
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. */ @Serial 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 protected boolean canEqual(Object other) { return other instanceof TextRegionLocation; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof TextRegionLocation that)) { return false; } return that.canEqual(this) && rawStartOffset == that.rawStartOffset && rawEndOffset == that.rawEndOffset && rawStartLine == that.rawStartLine && rawEndLine == that.rawEndLine && super.equals(that); } @Override public int hashCode() { return Objects.hash(super.hashCode(), rawStartOffset, rawEndOffset, rawStartLine, rawEndLine); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy