001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   https://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.bcel.generic;
020
021import java.util.Objects;
022
023import org.apache.bcel.classfile.LineNumber;
024
025/**
026 * This class represents a line number within a method, that is, give an instruction a line number corresponding to the
027 * source code line.
028 *
029 * @see LineNumber
030 * @see MethodGen
031 */
032public class LineNumberGen implements InstructionTargeter, Cloneable {
033
034    static final LineNumberGen[] EMPTY_ARRAY = {};
035
036    private InstructionHandle ih;
037    private int srcLine;
038
039    /**
040     * Create a line number.
041     *
042     * @param ih instruction handle to reference.
043     * @param srcLine source line number.
044     */
045    public LineNumberGen(final InstructionHandle ih, final int srcLine) {
046        setInstruction(ih);
047        setSourceLine(srcLine);
048    }
049
050    @Override
051    public Object clone() {
052        try {
053            return super.clone();
054        } catch (final CloneNotSupportedException e) {
055            throw new UnsupportedOperationException("Clone Not Supported", e); // never happens
056        }
057    }
058
059    /**
060     * @return true, if ih is target of this line number.
061     */
062    @Override
063    public boolean containsTarget(final InstructionHandle ih) {
064        return this.ih == ih;
065    }
066
067    /**
068     * Gets the instruction handle.
069     *
070     * @return The instruction handle.
071     */
072    public InstructionHandle getInstruction() {
073        return ih;
074    }
075
076    /**
077     * Gets LineNumber attribute.
078     *
079     * This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods
080     * has been called for the instruction list.
081     *
082     * @return The line number attribute.
083     */
084    public LineNumber getLineNumber() {
085        return new LineNumber(ih.getPosition(), srcLine);
086    }
087
088    /**
089     * Gets the source line number.
090     *
091     * @return The source line number.
092     */
093    public int getSourceLine() {
094        return srcLine;
095    }
096
097    /**
098     * Sets the instruction handle.
099     *
100     * @param instructionHandle The instruction handle to set.
101     */
102    public void setInstruction(final InstructionHandle instructionHandle) { // TODO could be package-protected?
103        Objects.requireNonNull(instructionHandle, "instructionHandle");
104        BranchInstruction.notifyTarget(this.ih, instructionHandle, this);
105        this.ih = instructionHandle;
106    }
107
108    /**
109     * Sets the source line number.
110     *
111     * @param srcLine The source line number to set.
112     */
113    public void setSourceLine(final int srcLine) { // TODO could be package-protected?
114        this.srcLine = srcLine;
115    }
116
117    /**
118     * @param oldIh old target.
119     * @param newIh new target.
120     */
121    @Override
122    public void updateTarget(final InstructionHandle oldIh, final InstructionHandle newIh) {
123        if (oldIh != ih) {
124            throw new ClassGenException("Not targeting " + oldIh + ", but " + ih + "}");
125        }
126        setInstruction(newIh);
127    }
128}