android.databinding.tool.store.Location.java Source code

Java tutorial

Introduction

Here is the source code for android.databinding.tool.store.Location.java

Source

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * 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 android.databinding.tool.store;

import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
import org.apache.commons.lang3.StringUtils;

import android.databinding.tool.processing.scopes.LocationScopeProvider;

import java.util.Arrays;
import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;

/**
 * Identifies the range of a code block inside a file or a string.
 * Note that, unlike antlr4 tokens, the line positions start from 0 (to be compatible with Studio).
 * <p>
 * Both start and end line/column indices are inclusive.
 */
@XmlAccessorType(XmlAccessType.NONE)
public class Location {
    public static final int NaN = -1;
    @XmlAttribute(name = "startLine")
    public int startLine;
    @XmlAttribute(name = "startOffset")
    public int startOffset;
    @XmlAttribute(name = "endLine")
    public int endLine;
    @XmlAttribute(name = "endOffset")
    public int endOffset;
    @XmlElement(name = "parentLocation")
    public Location parentLocation;

    // for XML unmarshalling
    public Location() {
        startOffset = endOffset = startLine = endLine = NaN;
    }

    public Location(Location other) {
        startOffset = other.startOffset;
        endOffset = other.endOffset;
        startLine = other.startLine;
        endLine = other.endLine;
    }

    public Location(Token start, Token end) {
        if (start == null) {
            startLine = startOffset = NaN;
        } else {
            startLine = start.getLine() - 1; //token lines start from 1
            startOffset = start.getCharPositionInLine();
        }

        if (end == null) {
            endLine = endOffset = NaN;
        } else {
            endLine = end.getLine() - 1; // token lines start from 1
            String endText = end.getText();
            int lastLineStart = endText.lastIndexOf(System.lineSeparator());
            String lastLine = lastLineStart < 0 ? endText : endText.substring(lastLineStart + 1);
            endOffset = end.getCharPositionInLine() + lastLine.length() - 1;//end is inclusive
        }
    }

    public Location(ParserRuleContext context) {
        this(context == null ? null : context.getStart(), context == null ? null : context.getStop());
    }

    public Location(int startLine, int startOffset, int endLine, int endOffset) {
        this.startOffset = startOffset;
        this.startLine = startLine;
        this.endLine = endLine;
        this.endOffset = endOffset;
    }

    @Override
    public String toString() {
        return "Location{" + "startLine=" + startLine + ", startOffset=" + startOffset + ", endLine=" + endLine
                + ", endOffset=" + endOffset + ", parentLocation=" + parentLocation + '}';
    }

    public void setParentLocation(Location parentLocation) {
        this.parentLocation = parentLocation;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        Location location = (Location) o;

        if (endLine != location.endLine) {
            return false;
        }
        if (endOffset != location.endOffset) {
            return false;
        }
        if (startLine != location.startLine) {
            return false;
        }
        if (startOffset != location.startOffset) {
            return false;
        }
        if (parentLocation != null ? !parentLocation.equals(location.parentLocation)
                : location.parentLocation != null) {
            return false;
        }

        return true;
    }

    @Override
    public int hashCode() {
        int result = startLine;
        result = 31 * result + startOffset;
        result = 31 * result + endLine;
        result = 31 * result + endOffset;
        return result;
    }

    public boolean isValid() {
        return startLine != NaN && endLine != NaN && startOffset != NaN && endOffset != NaN;
    }

    public boolean contains(Location other) {
        if (startLine > other.startLine) {
            return false;
        }
        if (startLine == other.startLine && startOffset > other.startOffset) {
            return false;
        }
        if (endLine < other.endLine) {
            return false;
        }
        if (endLine == other.endLine && endOffset < other.endOffset) {
            return false;
        }
        return true;
    }

    private Location getValidParentAbsoluteLocation() {
        if (parentLocation == null) {
            return null;
        }
        if (parentLocation.isValid()) {
            return parentLocation.toAbsoluteLocation();
        }
        return parentLocation.getValidParentAbsoluteLocation();
    }

    public Location toAbsoluteLocation() {
        Location absoluteParent = getValidParentAbsoluteLocation();
        if (absoluteParent == null) {
            return this;
        }
        Location copy = new Location(this);
        boolean sameLine = copy.startLine == copy.endLine;
        if (copy.startLine == 0) {
            copy.startOffset += absoluteParent.startOffset;
        }
        if (sameLine) {
            copy.endOffset += absoluteParent.startOffset;
        }

        copy.startLine += absoluteParent.startLine;
        copy.endLine += absoluteParent.startLine;
        return copy;
    }

    public String toUserReadableString() {
        return startLine + ":" + startOffset + " - " + endLine + ":" + endOffset;
    }

    public static Location fromUserReadableString(String str) {
        int glue = str.indexOf('-');
        if (glue == -1) {
            return new Location();
        }
        String start = str.substring(0, glue);
        String end = str.substring(glue + 1);
        int[] point = new int[] { -1, -1 };
        Location location = new Location();
        parsePoint(start, point);
        location.startLine = point[0];
        location.startOffset = point[1];
        point[0] = point[1] = -1;
        parsePoint(end, point);
        location.endLine = point[0];
        location.endOffset = point[1];
        return location;
    }

    private static boolean parsePoint(String content, int[] into) {
        int index = content.indexOf(':');
        if (index == -1) {
            return false;
        }
        into[0] = Integer.parseInt(content.substring(0, index).trim());
        into[1] = Integer.parseInt(content.substring(index + 1).trim());
        return true;
    }

    public LocationScopeProvider createScope() {
        return new LocationScopeProvider() {
            @Override
            public List<Location> provideScopeLocation() {
                return Arrays.asList(Location.this);
            }
        };
    }
}