Skip to content

Commit 7b36371

Browse files
committed
Merge pull request #645 from m0sth8/builtin_types
Add inspections for builtin functions with Type arguments (fixes #480)
2 parents 7686d5c + aeaf302 commit 7b36371

File tree

8 files changed

+126
-4
lines changed

8 files changed

+126
-4
lines changed

src/ro/redeul/google/go/lang/psi/expressions/primary/GoBuiltinCallExpression.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package ro.redeul.google.go.lang.psi.expressions.primary;
22

3+
import ro.redeul.google.go.lang.psi.types.GoPsiType;
4+
35
/**
46
* Author: Toader Mihai Claudiu <mtoader@gmail.com>
57
* <p/>
@@ -8,4 +10,5 @@
810
*/
911
public interface GoBuiltinCallExpression extends GoCallOrConvExpression {
1012

13+
public GoPsiType[] getArgumentsType();
1114
}

src/ro/redeul/google/go/lang/psi/impl/expressions/primary/GoBuiltinCallExpressionImpl.java

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@
1111
import ro.redeul.google.go.lang.psi.toplevel.GoMethodDeclaration;
1212
import ro.redeul.google.go.lang.psi.toplevel.GoPackageDeclaration;
1313
import ro.redeul.google.go.lang.psi.types.GoPsiType;
14+
import ro.redeul.google.go.lang.psi.types.GoPsiTypeMap;
15+
import ro.redeul.google.go.lang.psi.types.GoPsiTypeSlice;
1416
import ro.redeul.google.go.lang.psi.typing.GoType;
17+
import ro.redeul.google.go.lang.psi.typing.GoTypeMap;
18+
import ro.redeul.google.go.lang.psi.typing.GoTypeSlice;
1519
import ro.redeul.google.go.lang.psi.typing.GoTypes;
1620
import ro.redeul.google.go.lang.psi.visitors.GoElementVisitor;
1721
import ro.redeul.google.go.lang.stubs.GoNamesCache;
@@ -71,6 +75,67 @@ protected GoType[] resolveTypes() {
7175
return GoType.EMPTY_ARRAY;
7276
}
7377

78+
@Override
79+
public GoPsiType[] getArgumentsType() {
80+
PsiElement reference = resolveSafely(getBaseExpression(),
81+
PsiElement.class);
82+
83+
if (reference == null) {
84+
return processArgumentsType(this.getBaseExpression().getText());
85+
}
86+
87+
if (reference.getParent() instanceof GoFunctionDeclaration) {
88+
GoFunctionDeclaration declaration =
89+
(GoFunctionDeclaration) reference.getParent();
90+
91+
if (BUILTIN_FUNCTION.accepts(declaration))
92+
return processArgumentsType(declaration.getFunctionName());
93+
}
94+
95+
return GoPsiType.EMPTY_ARRAY;
96+
}
97+
98+
private GoPsiType[] processArgumentsType(String functionName) {
99+
GoNamesCache namesCache = GoNamesCache.getInstance(getProject());
100+
101+
GoExpr[] args = getArguments();
102+
GoPsiType typeArg = getTypeArgument();
103+
104+
if (functionName.equals("append")) {
105+
if (args.length > 1) {
106+
GoType[] types = args[0].getType();
107+
if (types.length > 0 && types[0] instanceof GoTypeSlice) {
108+
GoPsiTypeSlice appendedSlice = ((GoTypeSlice) types[0]).getPsiType();
109+
GoPsiType[] result = new GoPsiType[args.length];
110+
result[0] = appendedSlice;
111+
GoPsiType elem = appendedSlice.getElementType();
112+
for (int i = 1; i < args.length; i++){
113+
result[i] = elem;
114+
}
115+
return result;
116+
}
117+
}
118+
} else if (functionName.equals("copy")) {
119+
if (args.length == 2) {
120+
GoType[] types = args[0].getType();
121+
if (types.length > 0 && types[0] instanceof GoTypeSlice) {
122+
GoPsiTypeSlice copiedSlice = ((GoTypeSlice) types[0]).getPsiType();
123+
return new GoPsiType[]{copiedSlice, copiedSlice};
124+
}
125+
}
126+
} else if (functionName.equals("delete")) {
127+
if (args.length == 2) {
128+
GoType[] types = args[0].getType();
129+
if (types.length > 0 && types[0] instanceof GoTypeMap) {
130+
GoPsiTypeMap map = ((GoTypeMap) types[0]).getPsiType();
131+
return new GoPsiType[]{map, map.getKeyType()};
132+
}
133+
}
134+
}
135+
136+
return GoPsiType.EMPTY_ARRAY;
137+
}
138+
74139
private GoType[] processBuiltinFunction(String functionName) {
75140

76141
GoNamesCache namesCache = GoNamesCache.getInstance(getProject());
@@ -120,7 +185,7 @@ private GoType[] processBuiltinFunction(String functionName) {
120185
} else if (functionName.equals("append")) {
121186
if (args.length > 1) {
122187
GoType[] types = args[0].getType();
123-
if (types.length > 1) {
188+
if (types.length > 0) {
124189
return new GoType[]{types[0]};
125190
}
126191
}

src/ro/redeul/google/go/lang/psi/utils/GoExpressionUtils.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import ro.redeul.google.go.lang.psi.GoPsiElement;
99
import ro.redeul.google.go.lang.psi.expressions.GoPrimaryExpression;
1010
import ro.redeul.google.go.lang.psi.expressions.literals.GoLiteralIdentifier;
11+
import ro.redeul.google.go.lang.psi.expressions.primary.GoBuiltinCallExpression;
1112
import ro.redeul.google.go.lang.psi.expressions.primary.GoCallOrConvExpression;
1213
import ro.redeul.google.go.lang.psi.expressions.primary.GoLiteralExpression;
1314
import ro.redeul.google.go.lang.psi.expressions.primary.GoSelectorExpression;
@@ -17,6 +18,7 @@
1718
import static ro.redeul.google.go.lang.psi.utils.GoIdentifierUtils.getFunctionDeclaration;
1819
import static ro.redeul.google.go.lang.psi.utils.GoPsiUtils.findChildOfType;
1920
import static ro.redeul.google.go.lang.psi.utils.GoPsiUtils.findParentOfType;
21+
import static ro.redeul.google.go.lang.psi.utils.GoPsiUtils.resolveSafely;
2022

2123
public class GoExpressionUtils {
2224
@Nullable
@@ -47,6 +49,13 @@ public static GoPsiElement getCallFunctionIdentifier(@Nullable GoCallOrConvExpre
4749
*/
4850
@Nullable
4951
public static GoFunctionDeclaration resolveToFunctionDeclaration(@Nullable PsiElement element) {
52+
if (element instanceof GoBuiltinCallExpression){
53+
PsiElement reference = resolveSafely(((GoBuiltinCallExpression) element).getBaseExpression(),
54+
PsiElement.class);
55+
if (reference != null && reference.getParent() instanceof GoFunctionDeclaration){
56+
return (GoFunctionDeclaration) reference.getParent();
57+
}
58+
}
5059
GoCallOrConvExpression callExpr = findParentOfType(element, GoCallOrConvExpression.class);
5160
return getFunctionDeclaration(getCallFunctionIdentifier(callExpr));
5261
}

src/ro/redeul/google/go/util/GoTypeInspectUtil.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import ro.redeul.google.go.lang.psi.expressions.GoUnaryExpression;
1515
import ro.redeul.google.go.lang.psi.expressions.binary.GoBinaryExpression;
1616
import ro.redeul.google.go.lang.psi.expressions.literals.*;
17+
import ro.redeul.google.go.lang.psi.expressions.primary.GoBuiltinCallExpression;
1718
import ro.redeul.google.go.lang.psi.expressions.primary.GoCallOrConvExpression;
1819
import ro.redeul.google.go.lang.psi.expressions.primary.GoLiteralExpression;
1920
import ro.redeul.google.go.lang.psi.expressions.primary.GoParenthesisedExpression;
@@ -221,6 +222,24 @@ public static void checkFunctionTypeArguments(GoCallOrConvExpression call, Inspe
221222
if (goFunctionDeclaration == null)
222223
return;
223224

225+
if (call instanceof GoBuiltinCallExpression) {
226+
GoPsiType[] builtinTypes = ((GoBuiltinCallExpression) call).getArgumentsType();
227+
if (builtinTypes.length > 0 && goExprs.length == builtinTypes.length) {
228+
for (; index < goExprs.length; index++) {
229+
GoExpr goExpr = goExprs[index];
230+
GoPsiType type = builtinTypes[index];
231+
if (!checkParametersExp(type, goExpr)){
232+
result.addProblem(
233+
goExpr,
234+
GoBundle.message("warning.functioncall.type.mismatch", type.getText()),
235+
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new CastTypeFix(goExpr, type));
236+
return;
237+
}
238+
}
239+
}
240+
return;
241+
}
242+
224243
for (GoFunctionParameter functionParameter : goFunctionDeclaration.getParameters()) {
225244
if (index >= goExprs.length)
226245
return;

test/ro/redeul/google/go/inspection/FunctionCallInspectionTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@ public class FunctionCallInspectionTest extends GoInspectionTestCase {
55
public void testMake() throws Exception{ doTest(); }
66
public void testNew() throws Exception{ doTest(); }
77
public void testFuncCall() throws Exception{ doTest(); }
8+
public void testBuiltinCall() throws Exception{
9+
myFixture.addFileToProject("builtin.go", "package builtin\ntype Type int\ntype Type1 int\nfunc append(slice []Type, elems ...Type) []Type\nfunc copy(dst, src []Type) int\nfunc delete(m map[Type]Type1, key Type)\n");
10+
doTest();
11+
}
812
}

test/ro/redeul/google/go/inspection/GoInspectionTestCase.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ protected void doTest() throws Exception {
6868

6969
@Override
7070
protected void tearDown() throws Exception {
71-
removeContentRoots();
71+
// removeContentRoots();
7272
super.tearDown();
7373
}
7474

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package main
2+
3+
func main() {
4+
// issue #480
5+
arr1 := []int{}
6+
arr2 := []string{}
7+
arr3 := []byte{}
8+
arr1 = append(arr1, 1)
9+
arr1 = append(arr1, 1, 2, 3)
10+
arr1 = append(arr1, /*begin*/1.2/*end.Expression type mismatch, the expected type is int|CastTypeFix*/)
11+
arr1 = append(arr1, /*begin*/""/*end.Expression type mismatch, the expected type is int|CastTypeFix*/)
12+
13+
copy(arr1, arr1)
14+
copy(arr1, /*begin*/arr2/*end.Expression type mismatch, the expected type is []int|CastTypeFix*/)
15+
16+
map1 := map[string]int{}
17+
delete(map1, "key")
18+
delete(map1, /*begin*/1/*end.Expression type mismatch, the expected type is string|CastTypeFix*/)
19+
20+
// This test will be broken when issue #609 is fixed
21+
arr1 = append(arr1, /*begin*/arr1/*end.Expression type mismatch, the expected type is int|CastTypeFix*/...)
22+
arr3 = append(arr3, /*begin*/"test"/*end.Expression type mismatch, the expected type is byte|CastTypeFix*/...)
23+
24+
}

testdata/inspection/functionCall/funcCall.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,4 @@ func main() {
464464
myNewFnForTest := func(a string, b string) (bool,bool,bool) {return false,false,false}
465465
TestLiteralFunc(/*begin*/myNewFnForTest/*end.Expression type mismatch, the expected type is func(string,string)(bool,bool)|CastTypeFix*/)
466466
TestLiteralFunc(func(a string,b string)(bool,bool) {return false,true})
467-
468-
469467
}

0 commit comments

Comments
 (0)