/*
 * FindBugs - Find bugs in Java programs
 * Copyright (C) 2003-2005 University of Maryland
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package edu.umd.cs.findbugs.detect;


import edu.umd.cs.findbugs.*;
import java.util.*;
import org.apache.bcel.classfile.Method;

public class MutableLock extends BytecodeScanningDetector implements  StatelessDetector {
	Set<String> setFields = new HashSet<String>();
	boolean thisOnTOS = false;
	private BugReporter bugReporter;

	public MutableLock(BugReporter bugReporter) {
		this.bugReporter = bugReporter;
	}



	@Override
         public void visit(Method obj) {
		super.visit(obj);
		setFields.clear();
		thisOnTOS = false;
	}

	@Override
         public void sawOpcode(int seen) {

		switch (seen) {
		case ALOAD_0:
			thisOnTOS = true;
			return;
		case MONITOREXIT:
			setFields.clear();
			break;
		case PUTFIELD:
			if (getClassConstantOperand().equals(getClassName()))
				setFields.add(getNameConstantOperand());
			break;
		case GETFIELD:
			if (thisOnTOS && getClassConstantOperand().equals(getClassName())
			        && setFields.contains(getNameConstantOperand())
			        && asUnsignedByte(codeBytes[getPC() + 3]) == DUP
			        && asUnsignedByte(codeBytes[getPC() + 5]) == MONITORENTER
			)
				bugReporter.reportBug(new BugInstance(this, "ML_SYNC_ON_UPDATED_FIELD", NORMAL_PRIORITY)
				        .addClassAndMethod(this)
				        .addReferencedField(this)
				        .addSourceLine(this, getPC() + 5));
			break;
		default:
		}
		thisOnTOS = false;
	}
}

@@ -921,16 +921,101 @@
 .util.*;
+%0A%0Aimport org.apache.bcel.classfile.Field;%0Aimport org.apache.bcel.classfile.JavaClass;
 %0Aimport 
@@ -1187,16 +1187,66 @@
 ing%3E();%0A
+%09Set%3CString%3E finalFields = new HashSet%3CString%3E();%0A
 %09boolean
@@ -1386,16 +1386,228 @@
 r;%0A%09%7D%0A%0A%0A
+%09@Override%0A%09public void visit(JavaClass obj) %7B%0A%09%09finalFields.clear();%0A%09%09super.visit(obj);%0A%09%7D%0A%0A%09@Override%0A    public void visit(Field obj) %7B%0A%09super.visit(obj);%0A%09if (obj.isFinal()) finalFields.add(obj.getName());%0A%7D
 %0A%09@Overr
@@ -2293,16 +2293,90 @@
 ORENTER%0A
+%09%09%09        %0A%09%09%09        && !finalFields.contains(getNameConstantOperand())%0A
 %09%09%09)%0A%09%09%09

Fix for [ 1610605 ] ML: final field treated as updated field https://sourceforge.net/tracker/index.php?func=detail&aid=1610605&group_id=96405&atid=614693