Java: fix "Replace multiply with shift" intention for expressions with long type (IDEA-369236)

GitOrigin-RevId: 6122adad1f437c410371a9291b45ac4d187d2165
This commit is contained in:
Bas Leijdekkers
2025-03-15 23:09:06 +01:00
committed by intellij-monorepo-bot
parent a0d3056dfb
commit 9d7ba0dc56
7 changed files with 34 additions and 35 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2003-2022 Dave Griffith, Bas Leijdekkers
* Copyright 2003-2025 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -100,23 +100,10 @@ public final class ReplaceMultiplyWithShiftIntention extends MCIntention {
final PsiExpression lhs = expression.getLOperand();
final PsiExpression rhs = PsiUtil.skipParenthesizedExprDown(expression.getROperand());
final IElementType tokenType = expression.getOperationTokenType();
final String operatorString;
if (tokenType.equals(JavaTokenType.ASTERISK)) {
operatorString = "<<";
}
else {
operatorString = ">>";
}
final String lhsText;
if (ParenthesesUtils.getPrecedence(lhs) >
ParenthesesUtils.SHIFT_PRECEDENCE) {
lhsText = '(' + lhs.getText() + ')';
}
else {
lhsText = lhs.getText();
}
String expString =
lhsText + operatorString + ShiftUtils.getLogBase2(rhs);
final String operatorString = tokenType.equals(JavaTokenType.ASTERISK) ? "<<" : ">>";
final String lhsText = PsiTypes.intType().equals(lhs.getType()) && PsiTypes.longType().equals(expression.getType())
? "((long)" + lhs.getText() + ')' : lhs.getText();
String expString = lhsText + operatorString + ShiftUtils.getLogBase2(rhs);
final PsiElement parent = expression.getParent();
if (parent instanceof PsiExpression) {
if (!(parent instanceof PsiParenthesizedExpression) &&

View File

@@ -37,26 +37,16 @@ final class ShiftUtils {
if (value instanceof Double || value instanceof Float) {
return false;
}
int intValue = ((Number)value).intValue();
if (intValue <= 0) {
return false;
}
while (intValue % 2 == 0) {
intValue >>= 1;
}
return intValue == 1;
long v = ((Number)value).longValue();
return v > 0 && (v & (v - 1)) == 0; // https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2
}
public static int getLogBase2(PsiExpression rhs) {
public static long getLogBase2(PsiExpression rhs) {
final PsiLiteralExpression literal = (PsiLiteralExpression)rhs;
final Object value = literal.getValue();
int intValue = ((Number)value).intValue();
int log = 0;
while (intValue % 2 == 0) {
intValue >>= 1;
log++;
}
return log;
assert value != null;
long v = ((Number)value).longValue();
return 63 - Long.numberOfLeadingZeros(v);
}
public static boolean isIntegral(PsiType lhsType) {

View File

@@ -0,0 +1,5 @@
class Test {
void test(int foo) {
int x = 1; long y = x * <caret>4294967296L;
}
}

View File

@@ -0,0 +1,5 @@
class Test {
void test(int foo) {
int x = 1; long y = ((lo<caret>ng) x) << 32;
}
}

View File

@@ -0,0 +1,5 @@
class Test {
void test(int foo) {
long x = 1; long y = x * <caret>4294967296L;
}
}

View File

@@ -0,0 +1,5 @@
class Test {
void test(int foo) {
long x = 1; long y = x <<<caret> 32;
}
}

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.siyeh.ipp.shift;
import com.siyeh.ipp.IPPTestCase;
@@ -6,6 +6,8 @@ import com.siyeh.ipp.IPPTestCase;
public class ReplaceMultiplyWithShiftIntentionTest extends IPPTestCase {
public void testLeftShift() { doTest("Replace '*' with '<<'"); }
public void testLongShift() { doTest("Replace '*' with '<<'"); }
public void testCastedLongShift() { doTest("Replace '*' with '<<'"); }
public void testLeftShiftAssign() { doTest("Replace '*=' with '<<='"); }
public void testParentheses() { doTest("Replace '*' with '<<'"); }
public void testRightShift() { doTest("Replace '/' with '>>'"); }