Skip to content

Commit 543b24e

Browse files
committed
Rename "interesting" fields and methods
1 parent e68582b commit 543b24e

File tree

2 files changed

+50
-50
lines changed

2 files changed

+50
-50
lines changed

CHANGELOG.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@ Currently the versioning policy of this project follows [Semantic Versioning v2.
1010
- Do not consider Records as Singletons ([#2981](https://github.com/spotbugs/spotbugs/issues/2981))
1111
- Keep a maximum of 10000 cached analysis entries for plugin's analysis engines ([#3025](https://github.com/spotbugs/spotbugs/pull/3025))
1212

13+
### Added
14+
- New detector `AtomicOperationsCombinedDetector` and introduced new bug types:
15+
- `AT_COMBINED_ATOMIC_OPERATIONS_ARE_NOT_ATOMIC` is reported in case of combined atomic operations are not synchronized.
16+
- `AT_ATOMIC_OPERATION_NEEDS_SYNCHRONIZATION` is reported when an atomic operation is not synchronized, but should be because of thread safety.
17+
1318
## 4.8.6 - 2024-06-17
1419
### Fixed
1520
- Do not report BC_UNCONFIRMED_CAST for Java 21's type switches when the switch instruction is TABLESWITCH ([#2782](https://github.com/spotbugs/spotbugs/issues/2782))
1621
- Do not throw exception when inspecting empty switch statements ([#2995](https://github.com/spotbugs/spotbugs/issues/2995))
1722
- Adjust priority since relaxed mode reports even `IGNORED_PRIORITY` ([#2994](https://github.com/spotbugs/spotbugs/issues/2994))
1823
- Fix duplicated log4j2 jar in distribution ([#3001](https://github.com/spotbugs/spotbugs/issues/3001))
1924

20-
### Added
21-
- New detector `AtomicOperationsCombinedDetector` and introduced new bug types:
22-
- `AT_COMBINED_ATOMIC_OPERATIONS_ARE_NOT_ATOMIC` is reported in case of combined atomic operations are not synchronized.
23-
- `AT_ATOMIC_OPERATION_NEEDS_SYNCHRONIZATION` is reported when an atomic operation is not synchronized, but should be because of thread safety.
24-
2525
## 4.8.5 - 2024-05-03
2626
### Fixed
2727
- Fix FP `SING_SINGLETON_GETTER_NOT_SYNCHRONIZED` with eager instances ([#2932](https://github.com/spotbugs/spotbugs/issues/2932))

spotbugs/src/main/java/edu/umd/cs/findbugs/detect/AtomicOperationsCombinedDetector.java

+45-45
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,11 @@ private BugInstance toBugInstance(Detector detector, String type) {
101101
private final BugReporter bugReporter;
102102
private final BugAccumulator bugAccumulator;
103103

104-
private final Set<XField> interestingFields = new HashSet<>();
104+
private final Set<XField> fieldsForAtomicityCheck = new HashSet<>();
105105
private final Set<XField> combinedAtomicFields = new HashSet<>();
106106

107-
private final Map<Method, Map<XField, List<BugPrototype>>> interestingFieldCalls = new HashMap<>();
108-
private final Map<Method, List<BugPrototype>> interestingLocalVariableCalls = new HashMap<>();
107+
private final Map<Method, Map<XField, List<BugPrototype>>> fieldAccessBugPrototypes = new HashMap<>();
108+
private final Map<Method, List<BugPrototype>> localVariableInvocations = new HashMap<>();
109109

110110
private final Set<XMethod> unsynchronizedPrivateMethods = new HashSet<>();
111111

@@ -118,13 +118,13 @@ public AtomicOperationsCombinedDetector(BugReporter bugReporter) {
118118
public void visitClassContext(ClassContext classContext) {
119119
try {
120120
for (Method method : classContext.getMethodsInCallOrder()) {
121-
collectInterestingFields(classContext, method);
121+
collectFieldsForAtomicityCheck(classContext, method);
122122
}
123123
for (Method method : classContext.getMethodsInCallOrder()) {
124-
analyzeInterestingFields(classContext, method);
124+
analyzeFieldsForAtomicityViolations(classContext, method);
125125
}
126126
removePresynchronizedPrivateMethodCalls();
127-
accumulateInterestingFields();
127+
accumulateFieldsForAtomicityAnalysis();
128128
accumulateLocalVariables();
129129
} catch (CheckedAnalysisException e) {
130130
bugReporter.logError(String.format("Detector %s caught exception while analyzing class %s",
@@ -134,7 +134,7 @@ public void visitClassContext(ClassContext classContext) {
134134
}
135135
}
136136

137-
private void collectInterestingFields(ClassContext classContext, Method method) throws CFGBuilderException {
137+
private void collectFieldsForAtomicityCheck(ClassContext classContext, Method method) throws CFGBuilderException {
138138
CFG cfg = classContext.getCFG(method);
139139
ConstantPoolGen cpg = classContext.getConstantPoolGen();
140140

@@ -145,22 +145,22 @@ private void collectInterestingFields(ClassContext classContext, Method method)
145145
if (instruction instanceof PUTFIELD) {
146146
OpcodeStack stack = OpcodeStackScanner.getStackAt(classContext.getJavaClass(), method, handle.getPosition());
147147
OpcodeStack.Item stackItem = stack.getStackItem(0);
148-
if (isInterestingField(stackItem.getReturnValueOf())) {
149-
interestingFields.add(XFactory.createXField((FieldInstruction) instruction, cpg));
148+
if (isAtomicField(stackItem.getReturnValueOf())) {
149+
fieldsForAtomicityCheck.add(XFactory.createXField((FieldInstruction) instruction, cpg));
150150
}
151151
}
152152
}
153153
}
154154

155-
private static boolean isInterestingField(ClassMember classMember) {
155+
private static boolean isAtomicField(ClassMember classMember) {
156156
if (classMember == null) {
157157
return false;
158158
}
159159
return CollectionAnalysis.isSynchronizedCollection(classMember)
160160
|| (classMember.getClassName().startsWith("java.util.concurrent.atomic") && classMember.getSignature().endsWith(")V"));
161161
}
162162

163-
private void analyzeInterestingFields(ClassContext classContext, Method method) throws CheckedAnalysisException {
163+
private void analyzeFieldsForAtomicityViolations(ClassContext classContext, Method method) throws CheckedAnalysisException {
164164
if (Const.CONSTRUCTOR_NAME.equals(method.getName()) || Const.STATIC_INITIALIZER_NAME.equals(method.getName()) || method.isSynchronized()) {
165165
return;
166166
}
@@ -184,57 +184,57 @@ private void analyzeInterestingFields(ClassContext classContext, Method method)
184184
synchronizedBlock = false;
185185
} else if (instruction instanceof PUTFIELD && !synchronizedBlock && !MethodAnalysis.isDuplicatedLocation(methodDescriptor, pc)) {
186186
XField xField = XFactory.createXField((FieldInstruction) instruction, cpg);
187-
if (interestingFields.contains(xField)) {
187+
if (fieldsForAtomicityCheck.contains(xField)) {
188188
bugPrototype.invokedField = xField;
189-
interestingFieldCalls.computeIfAbsent(method, value -> new HashMap<>())
189+
fieldAccessBugPrototypes.computeIfAbsent(method, value -> new HashMap<>())
190190
.computeIfAbsent(xField, value -> new LinkedList<>())
191191
.add(bugPrototype);
192192
}
193193
} else if (instruction instanceof InvokeInstruction && !(instruction instanceof INVOKEDYNAMIC)
194194
&& !synchronizedBlock && !MethodAnalysis.isDuplicatedLocation(methodDescriptor, pc)) {
195195
OpcodeStack stack = OpcodeStackScanner.getStackAt(javaClass, method, pc);
196-
Optional<XField> interestingField = getInterestingField(stack);
196+
Optional<XField> fieldRequiringAtomicityCheck = findFieldRequiringAtomicityCheck(stack);
197197
XMethod xMethod = XFactory.createXMethod((InvokeInstruction) instruction, cpg);
198-
if (interestingField.isPresent()) {
199-
bugPrototype.invokedField = interestingField.get();
198+
if (fieldRequiringAtomicityCheck.isPresent()) {
199+
bugPrototype.invokedField = fieldRequiringAtomicityCheck.get();
200200
bugPrototype.invokedMethod = xMethod;
201-
interestingFieldCalls.computeIfAbsent(method, value -> new HashMap<>())
202-
.computeIfAbsent(interestingField.get(), value -> new LinkedList<>())
201+
fieldAccessBugPrototypes.computeIfAbsent(method, value -> new HashMap<>())
202+
.computeIfAbsent(fieldRequiringAtomicityCheck.get(), value -> new LinkedList<>())
203203
.add(bugPrototype);
204204

205205
if (javaClass.getClassName().equals(xMethod.getClassName())) {
206206
unsynchronizedPrivateMethods.add(xMethod);
207207
}
208208
} else if (stack.getStackDepth() > 0) {
209209
OpcodeStack.Item stackItem = stack.getStackItem(0);
210-
if (isInterestingLocalVariable(stackItem)) {
210+
if (isLocalVariableRequiringAtomicityCheck(stackItem)) {
211211
LocalVariableAnnotation annotation = LocalVariableAnnotation.getLocalVariableAnnotation(method, stackItem, pc);
212212
if (annotation != null) {
213213
bugPrototype.localVariableAnnotation = annotation;
214214
bugPrototype.invokedMethod = xMethod;
215-
interestingLocalVariableCalls.computeIfAbsent(method, value -> new LinkedList<>())
215+
localVariableInvocations.computeIfAbsent(method, value -> new LinkedList<>())
216216
.add(bugPrototype);
217217
}
218218
} else if (isAtomicOperationsCombined(stack)) {
219-
combinedAtomicFields.addAll(getInterestingFieldsInCall(location, callListDataflow));
219+
combinedAtomicFields.addAll(findFieldsInvolvedInAtomicOperations(location, callListDataflow));
220220
}
221221
}
222222
}
223223
}
224224
}
225225

226-
private Optional<XField> getInterestingField(OpcodeStack stack) {
226+
private Optional<XField> findFieldRequiringAtomicityCheck(OpcodeStack stack) {
227227
if (stack.getStackDepth() > 1 && stack.getStackItem(0).getReturnValueOf() != null) {
228228
return Optional.empty();
229229
}
230230
return IntStream.range(0, stack.getStackDepth())
231231
.mapToObj(stack::getStackItem)
232232
.map(OpcodeStack.Item::getXField)
233-
.filter(interestingFields::contains)
233+
.filter(fieldsForAtomicityCheck::contains)
234234
.findFirst();
235235
}
236236

237-
private static boolean isInterestingLocalVariable(OpcodeStack.Item stackItem) {
237+
private static boolean isLocalVariableRequiringAtomicityCheck(OpcodeStack.Item stackItem) {
238238
return isAtomicSignature(stackItem.getSignature())
239239
&& (stackItem.getReturnValueOf() == null || !stackItem.getReturnValueOf().getName().contains(Const.CONSTRUCTOR_NAME));
240240
}
@@ -253,21 +253,21 @@ private static boolean isAtomicReference(OpcodeStack.Item stackItem) {
253253
return stackItem.getReturnValueOf() != null && stackItem.getReturnValueOf().getClassName().startsWith("java.util.concurrent.atomic");
254254
}
255255

256-
private Set<XField> getInterestingFieldsInCall(Location location, CallListDataflow callListDataflow) throws DataflowAnalysisException {
257-
Set<XField> interestingFieldsInCallList = new HashSet<>();
256+
private Set<XField> findFieldsInvolvedInAtomicOperations(Location location, CallListDataflow callListDataflow) throws DataflowAnalysisException {
257+
Set<XField> involvedFields = new HashSet<>();
258258
CallList factAtLocation = callListDataflow.getFactAtLocation(location);
259259
Iterator<Call> callIterator = factAtLocation.callIterator();
260260
while (callIterator.hasNext()) {
261261
Call call = callIterator.next();
262262
call.getAttributes().stream()
263-
.filter(interestingFields::contains)
264-
.forEach(interestingFieldsInCallList::add);
263+
.filter(fieldsForAtomicityCheck::contains)
264+
.forEach(involvedFields::add);
265265
}
266-
return interestingFieldsInCallList;
266+
return involvedFields;
267267
}
268268

269269
private void removePresynchronizedPrivateMethodCalls() {
270-
interestingLocalVariableCalls.entrySet().removeIf(entry -> entry.getKey().isPrivate()
270+
localVariableInvocations.entrySet().removeIf(entry -> entry.getKey().isPrivate()
271271
&& unsynchronizedPrivateMethods.stream().noneMatch(privMethod -> equalMethods(entry.getKey(), privMethod)));
272272
}
273273

@@ -280,44 +280,44 @@ public void report() {
280280
bugAccumulator.reportAccumulatedBugs();
281281
}
282282

283-
private void accumulateInterestingFields() {
284-
Set<XField> interestingFieldsWithMultipleCalls = interestingFieldCalls.values().stream()
283+
private void accumulateFieldsForAtomicityAnalysis() {
284+
Set<XField> fieldsToProcess = fieldAccessBugPrototypes.values().stream()
285285
.flatMap(map -> map.entrySet().stream())
286286
.filter(entry -> entry.getValue().size() > 1)
287287
.map(Map.Entry::getKey)
288288
.collect(Collectors.toSet());
289289

290-
interestingFieldCalls.entrySet().stream()
290+
fieldAccessBugPrototypes.entrySet().stream()
291291
.flatMap(entry -> entry.getValue().entrySet().stream())
292-
.forEach(entry -> processFieldData(entry.getKey(), entry.getValue(), interestingFieldsWithMultipleCalls));
292+
.forEach(entry -> processFieldData(entry.getKey(), entry.getValue(), fieldsToProcess));
293293
}
294294

295295
private void accumulateLocalVariables() {
296-
interestingLocalVariableCalls.values().forEach(this::processFieldData);
296+
localVariableInvocations.values().forEach(this::processFieldData);
297297
}
298298

299-
private void processFieldData(List<BugPrototype> interestingFieldCallData) {
300-
processFieldData(null, interestingFieldCallData, new HashSet<>());
299+
private void processFieldData(List<BugPrototype> fieldCallData) {
300+
processFieldData(null, fieldCallData, new HashSet<>());
301301
}
302302

303-
private void processFieldData(XField field, List<BugPrototype> interestingFieldCallData, Set<XField> interestingFieldsWithMultipleCalls) {
304-
if (!interestingFieldCallData.isEmpty()) {
305-
BugPrototype bugPrototype = interestingFieldCallData.get(interestingFieldCallData.size() - 1);
306-
if (interestingFieldCallData.size() > 1 || combinedAtomicFields.contains(field)) {
303+
private void processFieldData(XField field, List<BugPrototype> fieldCallData, Set<XField> fieldsWithMultipleCalls) {
304+
if (!fieldCallData.isEmpty()) {
305+
BugPrototype bugPrototype = fieldCallData.get(fieldCallData.size() - 1);
306+
if (fieldCallData.size() > 1 || combinedAtomicFields.contains(field)) {
307307
BugInstance bugInstance = bugPrototype.toBugInstance(this, "AT_COMBINED_ATOMIC_OPERATIONS_ARE_NOT_ATOMIC");
308308
bugAccumulator.accumulateBug(bugInstance, bugInstance.getPrimarySourceLineAnnotation());
309-
} else if (interestingFieldsWithMultipleCalls.contains(field)) {
309+
} else if (fieldsWithMultipleCalls.contains(field)) {
310310
BugInstance bugInstance = bugPrototype.toBugInstance(this, "AT_ATOMIC_OPERATION_NEEDS_SYNCHRONIZATION");
311311
bugAccumulator.accumulateBug(bugInstance, bugInstance.getPrimarySourceLineAnnotation());
312312
}
313313
}
314314
}
315315

316316
private void clearProperties() {
317-
interestingFields.clear();
317+
fieldsForAtomicityCheck.clear();
318318
combinedAtomicFields.clear();
319-
interestingFieldCalls.clear();
320-
interestingLocalVariableCalls.clear();
319+
fieldAccessBugPrototypes.clear();
320+
localVariableInvocations.clear();
321321
unsynchronizedPrivateMethods.clear();
322322
}
323323
}

0 commit comments

Comments
 (0)