Skip to content

Commit 7a6714e

Browse files
committedFeb 22, 2024
7903680: Dependency checker doesn't handle function pointers and nested types
Reviewed-by: jvernee
1 parent 5e2dfec commit 7a6714e

File tree

3 files changed

+154
-9
lines changed

3 files changed

+154
-9
lines changed
 

‎src/main/java/org/openjdk/jextract/impl/MissingDepChecker.java

+32-9
Original file line numberDiff line numberDiff line change
@@ -48,35 +48,49 @@ public Declaration.Scoped scan(Declaration.Scoped header) {
4848
public Void visitFunction(Declaration.Function funcTree, Declaration parent) {
4949
if (Skip.isPresent(funcTree)) return null;
5050

51-
checkMissingDep(funcTree, funcTree.type().returnType());
52-
funcTree.type().argumentTypes().forEach(p -> checkMissingDep(funcTree, p));
51+
Declaration posDecl = posDecl(funcTree, parent);
52+
funcTree.parameters().forEach(p -> p.accept(this, posDecl));
53+
54+
Utils.forEachNested(funcTree, s -> s.accept(this, posDecl));
55+
56+
checkMissingDep(posDecl, funcTree.type());
5357
return null;
5458
}
5559

5660
@Override
5761
public Void visitScoped(Declaration.Scoped d, Declaration parent) {
5862
if (Skip.isPresent(d)) return null;
59-
60-
d.members().forEach(fieldTree -> fieldTree.accept(this, d));
63+
Declaration posDecl = posDecl(d, parent);
64+
d.members().forEach(fieldTree -> fieldTree.accept(this, posDecl));
6165
return null;
6266
}
6367

6468
@Override
6569
public Void visitTypedef(Declaration.Typedef tree, Declaration parent) {
6670
if (Skip.isPresent(tree)) return null;
6771

68-
checkMissingDep(tree, tree.type());
72+
Declaration posDecl = posDecl(tree, parent);
73+
Utils.forEachNested(tree, s -> s.accept(this, posDecl));
74+
75+
checkMissingDep(posDecl, tree.type());
76+
Type.Function func = Utils.getAsFunctionPointer(tree.type());
77+
if (func != null) {
78+
checkMissingDep(posDecl, func);
79+
}
6980
return null;
7081
}
7182

7283
@Override
7384
public Void visitVariable(Declaration.Variable tree, Declaration parent) {
7485
if (Skip.isPresent(tree)) return null;
7586

76-
if (parent != null && !Skip.isPresent(parent)) {
77-
checkMissingDep(parent, tree.type());
78-
} else {
79-
checkMissingDep(tree, tree.type());
87+
Declaration posDecl = posDecl(tree, parent);
88+
Utils.forEachNested(tree, s -> s.accept(this, posDecl));
89+
90+
checkMissingDep(posDecl, tree.type());
91+
Type.Function func = Utils.getAsFunctionPointer(tree.type());
92+
if (func != null) {
93+
checkMissingDep(posDecl, func);
8094
}
8195
return null;
8296
}
@@ -86,6 +100,15 @@ public Void visitDeclaration(Declaration decl, Declaration parent) {
86100
return null;
87101
}
88102

103+
Declaration posDecl(Declaration decl, Declaration parent) {
104+
return parent != null ? parent : decl;
105+
}
106+
107+
void checkMissingDep(Declaration decl, Type.Function function) {
108+
checkMissingDep(decl, function.returnType());
109+
function.argumentTypes().forEach(p -> checkMissingDep(decl, p));
110+
}
111+
89112
void checkMissingDep(Declaration decl, Type type) {
90113
if (type instanceof Type.Declared declared) {
91114
// we only have to check for missing structs because (a) pointers to missing structs can still lead
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
package org.openjdk.jextract.test.toolprovider.includeDeps;
25+
26+
import org.testng.annotations.BeforeClass;
27+
import org.testng.annotations.DataProvider;
28+
import org.testng.annotations.Test;
29+
import testlib.JextractToolRunner;
30+
31+
import java.nio.file.Path;
32+
import java.util.ArrayList;
33+
import java.util.List;
34+
import java.util.stream.Collectors;
35+
import java.util.stream.Stream;
36+
37+
public class TestNestedBadIncludes extends JextractToolRunner {
38+
39+
JextractResult result;
40+
41+
@BeforeClass
42+
public void before() {
43+
Path output = getOutputFilePath("TestNestedBadIncludes-nestedBadIncludes.h");
44+
Path outputH = getInputFilePath("nested_bad_includes.h");
45+
List<String> options = new ArrayList<>();
46+
Stream.of(cases()).flatMap(
47+
arr -> Stream.of((String)arr[0], (String)arr[1])
48+
).collect(Collectors.toCollection(() -> options));
49+
options.add(outputH.toString());
50+
result = run(output, options.toArray(new String[0]));
51+
result.checkFailure(FAILURE);
52+
}
53+
54+
@Test(dataProvider = "cases")
55+
public void testBadIncludes(String includeOption, String badDeclName, String missingDepName) {
56+
result.checkContainsOutput("ERROR: " + badDeclName + " depends on " + missingDepName);
57+
}
58+
59+
@DataProvider
60+
public static Object[][] cases() {
61+
return new Object[][]{
62+
{"--include-typedef", "t_str", "A" },
63+
{"--include-function", "f_str_arg", "A" },
64+
{"--include-function", "f_str_ret", "A" },
65+
{"--include-var", "v_str", "A" },
66+
{"--include-typedef", "t_fp_arg", "A" },
67+
{"--include-typedef", "t_fp_ret", "A" },
68+
{"--include-function", "f_fp_arg", "A" },
69+
{"--include-function", "f_fp_ret", "A" },
70+
{"--include-var", "v_fp_arg", "A" },
71+
{"--include-var", "v_fp_ret", "A" },
72+
};
73+
}
74+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
struct A { };
25+
26+
// nested
27+
28+
typedef struct { struct A a; } t_str;
29+
30+
void f_str_arg(struct { struct A a; });
31+
32+
struct { struct A a; } f_str_ret();
33+
34+
struct { struct A a; } v_str;
35+
36+
// function pointers
37+
38+
typedef void (*t_fp_arg)(struct A);
39+
40+
typedef struct A (*t_fp_ret)(int);
41+
42+
void f_fp_arg(void (*p)(struct A));
43+
44+
void f_fp_ret(struct A (*p)(int));
45+
46+
void (*v_fp_arg)(struct A);
47+
48+
struct A (*v_fp_ret)(int);

0 commit comments

Comments
 (0)
Please sign in to comment.