1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package org.chromium.tools.findbugs.plugin;
6
7import org.apache.bcel.classfile.Code;
8
9import edu.umd.cs.findbugs.BugInstance;
10import edu.umd.cs.findbugs.BugReporter;
11import edu.umd.cs.findbugs.bcel.OpcodeStackDetector;
12
13/**
14 * This class detects the synchronized(this).
15 *
16 * The pattern of byte code of synchronized(this) is
17 * aload_0         # Load the 'this' pointer on top of stack
18 * dup             # Duplicate the 'this' pointer
19 * astore_x        # Store this for late use, it might be astore.
20 * monitorenter
21 */
22public class SynchronizedThisDetector extends OpcodeStackDetector {
23    private final int PATTERN[] = {ALOAD_0, DUP, 0xff, 0xff, MONITORENTER};
24
25    private int mStep = 0;
26    private BugReporter mBugReporter;
27
28    public SynchronizedThisDetector(BugReporter bugReporter) {
29        mBugReporter = bugReporter;
30    }
31
32    @Override
33    public void visit(Code code) {
34        mStep = 0;
35        super.visit(code);
36    }
37
38    @Override
39    public void sawOpcode(int seen) {
40        if (PATTERN[mStep] == seen) {
41            mStep++;
42            if (mStep == PATTERN.length) {
43                mBugReporter.reportBug(new BugInstance(this, "CHROMIUM_SYNCHRONIZED_THIS",
44                                                       NORMAL_PRIORITY)
45                        .addClassAndMethod(this)
46                        .addSourceLine(this));
47                mStep = 0;
48                return;
49            }
50        } else if (mStep == 2) {
51            // This could be astore_x
52            switch (seen) {
53                case ASTORE_0:
54                case ASTORE_1:
55                case ASTORE_2:
56                case ASTORE_3:
57                    mStep += 2;
58                    break;
59                case ASTORE:
60                    mStep++;
61                    break;
62                default:
63                    mStep = 0;
64                    break;
65            }
66        } else if (mStep == 3) {
67            // Could be any byte following the ASTORE.
68            mStep++;
69        } else {
70            mStep = 0;
71        }
72    }
73}
74