mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-29 08:11:13 +00:00
ClangPlugins: Add LLVM lit test suite
This commit is contained in:
parent
6587c1f350
commit
46ee2b5f06
Notes:
sideshowbarker
2024-07-16 22:14:49 +09:00
Author: https://github.com/mattco98 Commit: https://github.com/SerenityOS/serenity/commit/46ee2b5f06 Pull-request: https://github.com/SerenityOS/serenity/pull/24027 Reviewed-by: https://github.com/ADKaster ✅ Reviewed-by: https://github.com/nico
38
Tests/ClangPlugins/CMakeLists.txt
Normal file
38
Tests/ClangPlugins/CMakeLists.txt
Normal file
|
@ -0,0 +1,38 @@
|
|||
find_package(Clang 17 CONFIG REQUIRED)
|
||||
find_package(LLVM 17 CONFIG REQUIRED)
|
||||
include(AddLLVM)
|
||||
|
||||
find_package(Python3 REQUIRED COMPONENTS Interpreter)
|
||||
|
||||
get_property(CLANG_PLUGINS_ALL_COMPILE_OPTIONS GLOBAL PROPERTY CLANG_PLUGINS_ALL_COMPILE_OPTIONS)
|
||||
list(APPEND CLANG_PLUGINS_ALL_COMPILE_OPTIONS -std=c++20 -Wno-user-defined-literals -Wno-literal-range)
|
||||
|
||||
get_property(CLANG_PLUGINS_INCLUDE_DIRECTORIES TARGET AK PROPERTY INCLUDE_DIRECTORIES)
|
||||
list(APPEND CLANG_PLUGINS_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
|
||||
|
||||
configure_lit_site_cfg(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py
|
||||
MAIN_CONFIG ${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py
|
||||
PATHS
|
||||
LLVM_BINARY_DIR
|
||||
LLVM_TOOLS_DIR
|
||||
LLVM_LIBS_DIR
|
||||
CMAKE_LIBRARY_OUTPUT_DIRECTORY
|
||||
CMAKE_CURRENT_SOURCE_DIR
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT venv
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/requirements.txt requirements.txt
|
||||
COMMAND ${Python3_EXECUTABLE} -m venv venv
|
||||
COMMAND ./venv/bin/pip install -r requirements.txt --upgrade
|
||||
)
|
||||
add_custom_target(TestClangPluginsDependencies ALL
|
||||
DEPENDS venv JSClangPlugin GenericClangPlugin
|
||||
SOURCES requirements.txt
|
||||
)
|
||||
add_test(
|
||||
NAME TestClangPlugins
|
||||
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/venv/bin/lit -v .
|
||||
)
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
// RUN: %clang++ -cc1 -verify %plugin_opts% %s 2>&1
|
||||
|
||||
#include <AK/Function.h>
|
||||
|
||||
// expected-note@+1 {{Annotate the parameter with NOESCAPE if the lambda will not outlive the function call}}
|
||||
void take_fn(Function<void()>) { }
|
||||
|
||||
void test()
|
||||
{
|
||||
// expected-note@+1 {{Annotate the variable declaration with IGNORE_USE_IN_ESCAPING_LAMBDA if it outlives the lambda}}
|
||||
int a = 0;
|
||||
|
||||
// expected-warning@+1 {{Variable with local storage is captured by reference in a lambda that may be asynchronously executed}}
|
||||
take_fn([&a] {
|
||||
(void)a;
|
||||
});
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
// RUN: %clang++ -cc1 -verify %plugin_opts% %s 2>&1
|
||||
// expected-no-diagnostics
|
||||
|
||||
#include <AK/Function.h>
|
||||
|
||||
void take_fn(Function<void()>) { }
|
||||
|
||||
void test()
|
||||
{
|
||||
IGNORE_USE_IN_ESCAPING_LAMBDA int a = 0;
|
||||
take_fn([&a] {
|
||||
(void)a;
|
||||
});
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
// RUN: %clang++ -cc1 -verify %plugin_opts% %s 2>&1
|
||||
// expected-no-diagnostics
|
||||
|
||||
#include <AK/Function.h>
|
||||
|
||||
void take_fn(NOESCAPE Function<void()>) { }
|
||||
|
||||
void test()
|
||||
{
|
||||
int a = 0;
|
||||
take_fn([&a] {
|
||||
(void)a;
|
||||
});
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
// RUN: %clang++ -cc1 -verify %plugin_opts% %s 2>&1
|
||||
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
|
||||
class TestClass : public JS::Object {
|
||||
JS_OBJECT(TestClass, JS::Object);
|
||||
|
||||
// expected-warning@+1 {{Missing call to Base::visit_edges}}
|
||||
virtual void visit_edges(Visitor& visitor) override
|
||||
{
|
||||
JS::Object::visit_edges(visitor);
|
||||
}
|
||||
};
|
63
Tests/ClangPlugins/LibJSGCTests/cell_member_not_wrapped.cpp
Normal file
63
Tests/ClangPlugins/LibJSGCTests/cell_member_not_wrapped.cpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
// RUN: %clang++ -cc1 -verify %plugin_opts% %s 2>&1
|
||||
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
|
||||
// Ensure it can see through typedefs
|
||||
typedef JS::Object NewType1;
|
||||
using NewType2 = JS::Object;
|
||||
|
||||
class TestClass : public JS::Object {
|
||||
JS_OBJECT(TestClass, JS::Object);
|
||||
|
||||
public:
|
||||
explicit TestClass(JS::Realm& realm, JS::Object& obj)
|
||||
: JS::Object(realm, nullptr)
|
||||
, m_object_ref(obj)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void visit_edges(Visitor& visitor) override
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_object_ref);
|
||||
visitor.visit(m_object_ptr);
|
||||
}
|
||||
|
||||
// expected-warning@+1 {{reference to JS::Cell type should be wrapped in JS::NonnullGCPtr}}
|
||||
JS::Object& m_object_ref;
|
||||
// expected-warning@+1 {{pointer to JS::Cell type should be wrapped in JS::GCPtr}}
|
||||
JS::Object* m_object_ptr;
|
||||
// expected-warning@+1 {{pointer to JS::Cell type should be wrapped in JS::GCPtr}}
|
||||
Vector<JS::Object*> m_objects;
|
||||
// expected-warning@+1 {{pointer to JS::Cell type should be wrapped in JS::GCPtr}}
|
||||
NewType1* m_newtype_1;
|
||||
// expected-warning@+1 {{pointer to JS::Cell type should be wrapped in JS::GCPtr}}
|
||||
NewType2* m_newtype_2;
|
||||
};
|
||||
|
||||
class TestClassNonCell {
|
||||
public:
|
||||
explicit TestClassNonCell(JS::Object& obj)
|
||||
: m_object_ref(obj)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
// expected-warning@+1 {{reference to JS::Cell type should be wrapped in JS::NonnullGCPtr}}
|
||||
JS::Object& m_object_ref;
|
||||
// expected-warning@+1 {{pointer to JS::Cell type should be wrapped in JS::GCPtr}}
|
||||
JS::Object* m_object_ptr;
|
||||
// expected-warning@+1 {{pointer to JS::Cell type should be wrapped in JS::GCPtr}}
|
||||
Vector<JS::Object*> m_objects;
|
||||
// expected-warning@+1 {{pointer to JS::Cell type should be wrapped in JS::GCPtr}}
|
||||
NewType1* m_newtype_1;
|
||||
// expected-warning@+1 {{pointer to JS::Cell type should be wrapped in JS::GCPtr}}
|
||||
NewType2* m_newtype_2;
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
// RUN: %clang++ -cc1 -verify %plugin_opts% %s 2>&1
|
||||
// expected-no-diagnostics
|
||||
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
|
||||
class TestClass : public JS::Object {
|
||||
JS_OBJECT(TestClass, JS::Object);
|
||||
|
||||
virtual void visit_edges(Visitor& visitor) override
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
|
||||
// FIXME: It might be nice to check that the object is specifically passed to .visit() or .ignore()
|
||||
(void)m_object;
|
||||
}
|
||||
|
||||
JS::GCPtr<JS::Object> m_object;
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
// RUN: %clang++ -cc1 -verify %plugin_opts% %s 2>&1
|
||||
// expected-no-diagnostics
|
||||
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
|
||||
class TestClass : public JS::Object {
|
||||
JS_OBJECT(TestClass, JS::Object);
|
||||
|
||||
virtual void visit_edges(Visitor& visitor) override
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_object);
|
||||
}
|
||||
|
||||
JS::GCPtr<JS::Object> m_object;
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
// RUN: %clang++ -cc1 -verify %plugin_opts% %s 2>&1
|
||||
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
|
||||
class TestClass : public JS::Object {
|
||||
JS_OBJECT(TestClass, JS::Object);
|
||||
|
||||
// expected-warning@+1 {{Missing call to Base::visit_edges}}
|
||||
virtual void visit_edges(Visitor&) override
|
||||
{
|
||||
}
|
||||
};
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
// RUN: %clang++ -cc1 -verify %plugin_opts% %s 2>&1
|
||||
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
|
||||
class TestClass : public JS::Object {
|
||||
JS_OBJECT(TestClass, JS::Object);
|
||||
|
||||
virtual void visit_edges(Visitor& visitor) override
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
}
|
||||
|
||||
// expected-warning@+1 {{GC-allocated member is not visited in TestClass::visit_edges}}
|
||||
JS::GCPtr<JS::Object> m_object;
|
||||
};
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
// RUN: %clang++ -cc1 -verify %plugin_opts% %s 2>&1
|
||||
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
|
||||
// expected-warning@+1 {{JS::Cell-inheriting class TestClass contains a GC-allocated member 'm_cell' but has no visit_edges method}}
|
||||
class TestClass : public JS::Object {
|
||||
JS_OBJECT(TestClass, JS::Object);
|
||||
|
||||
JS::GCPtr<JS::Object> m_cell;
|
||||
};
|
14
Tests/ClangPlugins/LibJSGCTests/non_cell_class.cpp
Normal file
14
Tests/ClangPlugins/LibJSGCTests/non_cell_class.cpp
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
// RUN: %clang++ -cc1 -verify %plugin_opts% %s 2>&1
|
||||
// expected-no-diagnostics
|
||||
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
|
||||
class NonCell {
|
||||
JS::GCPtr<JS::Object> m_object;
|
||||
};
|
16
Tests/ClangPlugins/LibJSGCTests/not_visiting_rawgcptr.cpp
Normal file
16
Tests/ClangPlugins/LibJSGCTests/not_visiting_rawgcptr.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
// RUN: %clang++ -cc1 -verify %plugin_opts% %s 2>&1
|
||||
// expected-no-diagnostics
|
||||
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
|
||||
class TestClass : public JS::Object {
|
||||
JS_OBJECT(TestClass, JS::Object);
|
||||
|
||||
JS::RawGCPtr<JS::Object> m_object;
|
||||
};
|
21
Tests/ClangPlugins/LibJSGCTests/wrapping_non_cell_member.cpp
Normal file
21
Tests/ClangPlugins/LibJSGCTests/wrapping_non_cell_member.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
// RUN: %clang++ -cc1 -verify %plugin_opts% %s 2>&1
|
||||
|
||||
#include <LibJS/Heap/GCPtr.h>
|
||||
#include <LibJS/Heap/MarkedVector.h>
|
||||
|
||||
struct NotACell { };
|
||||
|
||||
class TestClass {
|
||||
// expected-warning@+1 {{Specialization type must inherit from JS::Cell}}
|
||||
JS::GCPtr<NotACell> m_member_1;
|
||||
// expected-warning@+1 {{Specialization type must inherit from JS::Cell}}
|
||||
JS::NonnullGCPtr<NotACell> m_member_2;
|
||||
// expected-warning@+1 {{Specialization type must inherit from JS::Cell}}
|
||||
JS::RawGCPtr<NotACell> m_member_3;
|
||||
};
|
25
Tests/ClangPlugins/lit.cfg.py
Normal file
25
Tests/ClangPlugins/lit.cfg.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Disable flake linting for this file since it flags "config" as a non-existent variable
|
||||
# flake8: noqa
|
||||
|
||||
import os
|
||||
import lit.formats
|
||||
import lit.util
|
||||
from lit.llvm import llvm_config
|
||||
from lit.llvm.subst import ToolSubst
|
||||
from lit.llvm.subst import FindTool
|
||||
|
||||
config.name = "ClangPlugins"
|
||||
config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell)
|
||||
config.suffixes = [".cpp"]
|
||||
config.test_source_root = os.path.dirname(__file__)
|
||||
llvm_config.use_default_substitutions()
|
||||
llvm_config.use_clang()
|
||||
config.substitutions.append(("%target_triple", config.target_triple))
|
||||
config.substitutions.append(("%PATH%", config.environment["PATH"]))
|
||||
|
||||
plugin_includes = " ".join(f"-I{s}" for s in config.plugin_includes.split(";"))
|
||||
plugin_opts = " ".join(s.replace("-fplugin=", "-load ") for s in config.plugin_opts.split(";"))
|
||||
config.substitutions.append(("%plugin_opts%", f"{plugin_opts} {plugin_includes}"))
|
||||
|
||||
tools = ["clang", "clang++"]
|
||||
llvm_config.add_tool_substitutions(tools, config.llvm_tools_dir)
|
29
Tests/ClangPlugins/lit.site.cfg.py.in
Normal file
29
Tests/ClangPlugins/lit.site.cfg.py.in
Normal file
|
@ -0,0 +1,29 @@
|
|||
@LIT_SITE_CFG_IN_HEADER@
|
||||
|
||||
import sys
|
||||
|
||||
config.llvm_obj_root = path(r"@LLVM_BINARY_DIR@")
|
||||
config.llvm_tools_dir = lit_config.substitute(path(r"@LLVM_TOOLS_DIR@"))
|
||||
config.llvm_libs_dir = lit_config.substitute(path(r"@LLVM_LIBS_DIR@"))
|
||||
config.llvm_shlib_dir = lit_config.substitute(path(r"@CMAKE_LIBRARY_OUTPUT_DIRECTORY@"))
|
||||
config.llvm_plugin_ext = "@LLVM_PLUGIN_EXT@"
|
||||
config.clang_lit_site_cfg = __file__
|
||||
config.clang_lib_dir = path(r"@CMAKE_LIBRARY_OUTPUT_DIRECTORY@")
|
||||
config.host_triple = "@LLVM_HOST_TRIPLE@"
|
||||
config.target_triple = "@LLVM_TARGET_TRIPLE@"
|
||||
config.host_cc = "@CMAKE_C_COMPILER@"
|
||||
config.host_cxx = "@CMAKE_CXX_COMPILER@"
|
||||
config.have_zlib = @LLVM_ENABLE_ZLIB@
|
||||
config.enable_shared = @ENABLE_SHARED@
|
||||
config.host_arch = "@HOST_ARCH@"
|
||||
config.python_executable = "@Python3_EXECUTABLE@"
|
||||
# config.has_plugins = @CLANG_PLUGIN_SUPPORT@
|
||||
config.plugin_opts = "@CLANG_PLUGINS_ALL_COMPILE_OPTIONS@"
|
||||
config.plugin_includes = "@CLANG_PLUGINS_INCLUDE_DIRECTORIES@"
|
||||
|
||||
import lit.llvm
|
||||
lit.llvm.initialize(lit_config, config)
|
||||
|
||||
# Let the main config do the real work.
|
||||
lit_config.load_config(
|
||||
config, os.path.join(path("@CMAKE_CURRENT_SOURCE_DIR@"), "lit.cfg.py"))
|
1
Tests/ClangPlugins/requirements.txt
Normal file
1
Tests/ClangPlugins/requirements.txt
Normal file
|
@ -0,0 +1 @@
|
|||
lit==18.1.3
|
Loading…
Reference in a new issue