423 lines
19 KiB
C++
423 lines
19 KiB
C++
//===- unittest/Format/ObjCPropertyAttributeOrderFixerTest.cpp - unit tests
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "../lib/Format/ObjCPropertyAttributeOrderFixer.h"
|
|
#include "FormatTestBase.h"
|
|
#include "TestLexer.h"
|
|
|
|
#define DEBUG_TYPE "format-objc-property-attribute-order-fixer-test"
|
|
|
|
namespace clang {
|
|
namespace format {
|
|
namespace test {
|
|
namespace {
|
|
|
|
#define CHECK_PARSE(TEXT, FIELD, VALUE) \
|
|
EXPECT_NE(VALUE, Style.FIELD) << "Initial value already the same!"; \
|
|
EXPECT_EQ(0, parseConfiguration(TEXT, &Style).value()); \
|
|
EXPECT_EQ(VALUE, Style.FIELD) << "Unexpected value after parsing!"
|
|
|
|
#define FAIL_PARSE(TEXT, FIELD, VALUE) \
|
|
EXPECT_NE(0, parseConfiguration(TEXT, &Style).value()); \
|
|
EXPECT_EQ(VALUE, Style.FIELD) << "Unexpected value after parsing!"
|
|
|
|
class ObjCPropertyAttributeOrderFixerTest : public FormatTestBase {
|
|
protected:
|
|
TokenList annotate(llvm::StringRef Code,
|
|
const FormatStyle &Style = getLLVMStyle()) {
|
|
return TestLexer(Allocator, Buffers, Style).annotate(Code);
|
|
}
|
|
|
|
llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;
|
|
std::vector<std::unique_ptr<llvm::MemoryBuffer>> Buffers;
|
|
};
|
|
|
|
TEST_F(ObjCPropertyAttributeOrderFixerTest, ParsesStyleOption) {
|
|
FormatStyle Style = {};
|
|
Style.Language = FormatStyle::LK_ObjC;
|
|
|
|
CHECK_PARSE("ObjCPropertyAttributeOrder: [class]", ObjCPropertyAttributeOrder,
|
|
std::vector<std::string>({"class"}));
|
|
|
|
CHECK_PARSE("ObjCPropertyAttributeOrder: ["
|
|
"class, direct, atomic, nonatomic, "
|
|
"assign, retain, strong, copy, weak, unsafe_unretained, "
|
|
"readonly, readwrite, getter, setter, "
|
|
"nullable, nonnull, null_resettable, null_unspecified"
|
|
"]",
|
|
ObjCPropertyAttributeOrder,
|
|
std::vector<std::string>({
|
|
"class",
|
|
"direct",
|
|
"atomic",
|
|
"nonatomic",
|
|
"assign",
|
|
"retain",
|
|
"strong",
|
|
"copy",
|
|
"weak",
|
|
"unsafe_unretained",
|
|
"readonly",
|
|
"readwrite",
|
|
"getter",
|
|
"setter",
|
|
"nullable",
|
|
"nonnull",
|
|
"null_resettable",
|
|
"null_unspecified",
|
|
}));
|
|
}
|
|
|
|
TEST_F(ObjCPropertyAttributeOrderFixerTest, SortsSpecifiedAttributes) {
|
|
FormatStyle Style = getLLVMStyle();
|
|
Style.Language = FormatStyle::LK_ObjC;
|
|
Style.ObjCPropertyAttributeOrder = {"a", "b", "c"};
|
|
|
|
// Zero: nothing to do, but is legal.
|
|
verifyFormat("@property() int p;", Style);
|
|
|
|
// One: shouldn't move.
|
|
verifyFormat("@property(a) int p;", Style);
|
|
verifyFormat("@property(b) int p;", Style);
|
|
verifyFormat("@property(c) int p;", Style);
|
|
|
|
// Two in correct order already: no change.
|
|
verifyFormat("@property(a, b) int p;", Style);
|
|
verifyFormat("@property(a, c) int p;", Style);
|
|
verifyFormat("@property(b, c) int p;", Style);
|
|
|
|
// Three in correct order already: no change.
|
|
verifyFormat("@property(a, b, c) int p;", Style);
|
|
|
|
// Two wrong order.
|
|
verifyFormat("@property(a, b) int p;", "@property(b, a) int p;", Style);
|
|
verifyFormat("@property(a, c) int p;", "@property(c, a) int p;", Style);
|
|
verifyFormat("@property(b, c) int p;", "@property(c, b) int p;", Style);
|
|
|
|
// Three wrong order.
|
|
verifyFormat("@property(a, b, c) int p;", "@property(b, a, c) int p;", Style);
|
|
verifyFormat("@property(a, b, c) int p;", "@property(c, b, a) int p;", Style);
|
|
|
|
// Check that properties preceded by @optional/@required work.
|
|
verifyFormat("@optional\n"
|
|
"@property(a, b) int p;",
|
|
"@optional @property(b, a) int p;", Style);
|
|
verifyFormat("@required\n"
|
|
"@property(a, b) int p;",
|
|
"@required @property(b, a) int p;", Style);
|
|
|
|
// Check two `@property`s on one-line are reflowed (by other passes)
|
|
// and both have their attributes reordered.
|
|
verifyFormat("@property(a, b) int p;\n"
|
|
"@property(a, b) int q;",
|
|
"@property(b, a) int p; @property(b, a) int q;", Style);
|
|
}
|
|
|
|
TEST_F(ObjCPropertyAttributeOrderFixerTest, SortsAttributesWithValues) {
|
|
FormatStyle Style = getLLVMStyle();
|
|
Style.Language = FormatStyle::LK_ObjC;
|
|
Style.ObjCPropertyAttributeOrder = {"a", "getter", "c"};
|
|
|
|
// No change
|
|
verifyFormat("@property(getter=G, c) int p;", Style);
|
|
verifyFormat("@property(a, getter=G) int p;", Style);
|
|
verifyFormat("@property(a, getter=G, c) int p;", Style);
|
|
|
|
// Reorder
|
|
verifyFormat("@property(getter=G, c) int p;", "@property(c, getter=G) int p;",
|
|
Style);
|
|
verifyFormat("@property(a, getter=G) int p;", "@property(getter=G, a) int p;",
|
|
Style);
|
|
verifyFormat("@property(a, getter=G, c) int p;",
|
|
"@property(getter=G, c, a) int p;", Style);
|
|
|
|
// Multiple set properties, including ones not recognized
|
|
verifyFormat("@property(a=A, c=C, x=X, y=Y) int p;",
|
|
"@property(c=C, x=X, y=Y, a=A) int p;", Style);
|
|
}
|
|
|
|
TEST_F(ObjCPropertyAttributeOrderFixerTest, SortsUnspecifiedAttributesToBack) {
|
|
FormatStyle Style = getLLVMStyle();
|
|
Style.Language = FormatStyle::LK_ObjC;
|
|
Style.ObjCPropertyAttributeOrder = {"a", "b", "c"};
|
|
|
|
verifyFormat("@property(x) int p;", Style);
|
|
|
|
// No change in order.
|
|
verifyFormat("@property(a, x, y) int p;", Style);
|
|
verifyFormat("@property(b, x, y) int p;", Style);
|
|
verifyFormat("@property(a, b, c, x, y) int p;", Style);
|
|
|
|
// Reorder one unrecognized one.
|
|
verifyFormat("@property(a, x) int p;", "@property(x, a) int p;", Style);
|
|
|
|
// Prove the unrecognized ones have a stable sort order
|
|
verifyFormat("@property(a, b, x, y) int p;", "@property(x, b, y, a) int p;",
|
|
Style);
|
|
verifyFormat("@property(a, b, y, x) int p;", "@property(y, b, x, a) int p;",
|
|
Style);
|
|
}
|
|
|
|
TEST_F(ObjCPropertyAttributeOrderFixerTest, HandlesDuplicatedAttributes) {
|
|
// Duplicated attributes aren't rejected by the compiler even if it's silly
|
|
// to do so. Preserve them and sort them best-effort.
|
|
FormatStyle Style = getLLVMStyle();
|
|
Style.Language = FormatStyle::LK_ObjC;
|
|
Style.ObjCPropertyAttributeOrder = {"a", "b", "c"};
|
|
|
|
// Just a dup and nothing else.
|
|
verifyFormat("@property(a) int p;", "@property(a, a) int p;", Style);
|
|
|
|
// A dup and something else.
|
|
verifyFormat("@property(a, b) int p;", "@property(a, b, a) int p;", Style);
|
|
|
|
// Duplicates using `=`.
|
|
verifyFormat("@property(a=A, b=X) int p;",
|
|
"@property(a=A, b=X, a=A, b=Y) int p;", Style);
|
|
verifyFormat("@property(a=A, b=Y) int p;",
|
|
"@property(a=A, b=Y, a=A, b=X) int p;", Style);
|
|
verifyFormat("@property(a, b=B) int p;", "@property(a, b=B, a=A, b) int p;",
|
|
Style);
|
|
}
|
|
|
|
TEST_F(ObjCPropertyAttributeOrderFixerTest, SortsInPPDirective) {
|
|
FormatStyle Style = getLLVMStyle();
|
|
Style.Language = FormatStyle::LK_ObjC;
|
|
Style.ObjCPropertyAttributeOrder = {"a", "b", "c"};
|
|
|
|
// Spot-check a few simple cases that require sorting in a macro definition.
|
|
verifyFormat("#define MACRO @property() int p;", Style);
|
|
verifyFormat("#define MACRO @property(a) int p;", Style);
|
|
verifyFormat("#define MACRO @property(a, b) int p;",
|
|
"#define MACRO @property(b, a) int p;", Style);
|
|
verifyFormat("#define MACRO @property(a, b, c) int p;",
|
|
"#define MACRO @property(c, b, a) int p;", Style);
|
|
}
|
|
|
|
TEST_F(ObjCPropertyAttributeOrderFixerTest, HandlesAllAttributes) {
|
|
// `class` is the only attribute that is a keyword, so make sure it works too.
|
|
FormatStyle Style = getLLVMStyle();
|
|
Style.Language = FormatStyle::LK_ObjC;
|
|
Style.ObjCPropertyAttributeOrder = {"FIRST",
|
|
"class",
|
|
"direct",
|
|
"atomic",
|
|
"nonatomic",
|
|
"assign",
|
|
"retain",
|
|
"strong",
|
|
"copy",
|
|
"weak",
|
|
"unsafe_unretained",
|
|
"readonly",
|
|
"readwrite",
|
|
"getter",
|
|
"setter",
|
|
"nullable",
|
|
"nonnull",
|
|
"null_resettable",
|
|
"null_unspecified",
|
|
"LAST"};
|
|
|
|
// No change: specify all attributes in the correct order.
|
|
verifyFormat("@property(class, LAST) int p;", Style);
|
|
verifyFormat("@property(direct, LAST) int p;", Style);
|
|
verifyFormat("@property(atomic, LAST) int p;", Style);
|
|
verifyFormat("@property(nonatomic, LAST) int p;", Style);
|
|
verifyFormat("@property(assign, LAST) int p;", Style);
|
|
verifyFormat("@property(retain, LAST) int p;", Style);
|
|
verifyFormat("@property(strong, LAST) int p;", Style);
|
|
verifyFormat("@property(copy, LAST) int p;", Style);
|
|
verifyFormat("@property(weak, LAST) int p;", Style);
|
|
verifyFormat("@property(unsafe_unretained, LAST) int p;", Style);
|
|
verifyFormat("@property(readonly, LAST) int p;", Style);
|
|
verifyFormat("@property(readwrite, LAST) int p;", Style);
|
|
verifyFormat("@property(getter, LAST) int p;", Style);
|
|
verifyFormat("@property(setter, LAST) int p;", Style);
|
|
verifyFormat("@property(nullable, LAST) int p;", Style);
|
|
verifyFormat("@property(nonnull, LAST) int p;", Style);
|
|
verifyFormat("@property(null_resettable, LAST) int p;", Style);
|
|
verifyFormat("@property(null_unspecified, LAST) int p;", Style);
|
|
|
|
verifyFormat("@property(FIRST, class) int p;", Style);
|
|
verifyFormat("@property(FIRST, direct) int p;", Style);
|
|
verifyFormat("@property(FIRST, atomic) int p;", Style);
|
|
verifyFormat("@property(FIRST, nonatomic) int p;", Style);
|
|
verifyFormat("@property(FIRST, assign) int p;", Style);
|
|
verifyFormat("@property(FIRST, retain) int p;", Style);
|
|
verifyFormat("@property(FIRST, strong) int p;", Style);
|
|
verifyFormat("@property(FIRST, copy) int p;", Style);
|
|
verifyFormat("@property(FIRST, weak) int p;", Style);
|
|
verifyFormat("@property(FIRST, unsafe_unretained) int p;", Style);
|
|
verifyFormat("@property(FIRST, readonly) int p;", Style);
|
|
verifyFormat("@property(FIRST, readwrite) int p;", Style);
|
|
verifyFormat("@property(FIRST, getter) int p;", Style);
|
|
verifyFormat("@property(FIRST, setter) int p;", Style);
|
|
verifyFormat("@property(FIRST, nullable) int p;", Style);
|
|
verifyFormat("@property(FIRST, nonnull) int p;", Style);
|
|
verifyFormat("@property(FIRST, null_resettable) int p;", Style);
|
|
verifyFormat("@property(FIRST, null_unspecified) int p;", Style);
|
|
|
|
verifyFormat("@property(FIRST, class, LAST) int p;", Style);
|
|
verifyFormat("@property(FIRST, direct, LAST) int p;", Style);
|
|
verifyFormat("@property(FIRST, atomic, LAST) int p;", Style);
|
|
verifyFormat("@property(FIRST, nonatomic, LAST) int p;", Style);
|
|
verifyFormat("@property(FIRST, assign, LAST) int p;", Style);
|
|
verifyFormat("@property(FIRST, retain, LAST) int p;", Style);
|
|
verifyFormat("@property(FIRST, strong, LAST) int p;", Style);
|
|
verifyFormat("@property(FIRST, copy, LAST) int p;", Style);
|
|
verifyFormat("@property(FIRST, weak, LAST) int p;", Style);
|
|
verifyFormat("@property(FIRST, unsafe_unretained, LAST) int p;", Style);
|
|
verifyFormat("@property(FIRST, readonly, LAST) int p;", Style);
|
|
verifyFormat("@property(FIRST, readwrite, LAST) int p;", Style);
|
|
verifyFormat("@property(FIRST, getter, LAST) int p;", Style);
|
|
verifyFormat("@property(FIRST, setter, LAST) int p;", Style);
|
|
verifyFormat("@property(FIRST, nullable, LAST) int p;", Style);
|
|
verifyFormat("@property(FIRST, nonnull, LAST) int p;", Style);
|
|
verifyFormat("@property(FIRST, null_resettable, LAST) int p;", Style);
|
|
verifyFormat("@property(FIRST, null_unspecified, LAST) int p;", Style);
|
|
|
|
// Reorder: put `FIRST` and/or `LAST` in the wrong spot.
|
|
verifyFormat("@property(class, LAST) int p;", "@property(LAST, class) int p;",
|
|
Style);
|
|
verifyFormat("@property(direct, LAST) int p;",
|
|
"@property(LAST, direct) int p;", Style);
|
|
verifyFormat("@property(atomic, LAST) int p;",
|
|
"@property(LAST, atomic) int p;", Style);
|
|
verifyFormat("@property(nonatomic, LAST) int p;",
|
|
"@property(LAST, nonatomic) int p;", Style);
|
|
verifyFormat("@property(assign, LAST) int p;",
|
|
"@property(LAST, assign) int p;", Style);
|
|
verifyFormat("@property(retain, LAST) int p;",
|
|
"@property(LAST, retain) int p;", Style);
|
|
verifyFormat("@property(strong, LAST) int p;",
|
|
"@property(LAST, strong) int p;", Style);
|
|
verifyFormat("@property(copy, LAST) int p;", "@property(LAST, copy) int p;",
|
|
Style);
|
|
verifyFormat("@property(weak, LAST) int p;", "@property(LAST, weak) int p;",
|
|
Style);
|
|
verifyFormat("@property(unsafe_unretained, LAST) int p;",
|
|
"@property(LAST, unsafe_unretained) int p;", Style);
|
|
verifyFormat("@property(readonly, LAST) int p;",
|
|
"@property(LAST, readonly) int p;", Style);
|
|
verifyFormat("@property(readwrite, LAST) int p;",
|
|
"@property(LAST, readwrite) int p;", Style);
|
|
verifyFormat("@property(getter, LAST) int p;",
|
|
"@property(LAST, getter) int p;", Style);
|
|
verifyFormat("@property(setter, LAST) int p;",
|
|
"@property(LAST, setter) int p;", Style);
|
|
verifyFormat("@property(nullable, LAST) int p;",
|
|
"@property(LAST, nullable) int p;", Style);
|
|
verifyFormat("@property(nonnull, LAST) int p;",
|
|
"@property(LAST, nonnull) int p;", Style);
|
|
verifyFormat("@property(null_resettable, LAST) int p;",
|
|
"@property(LAST, null_resettable) int p;", Style);
|
|
verifyFormat("@property(null_unspecified, LAST) int p;",
|
|
"@property(LAST, null_unspecified) int p;", Style);
|
|
|
|
verifyFormat("@property(FIRST, class) int p;",
|
|
"@property(class, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, direct) int p;",
|
|
"@property(direct, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, atomic) int p;",
|
|
"@property(atomic, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, nonatomic) int p;",
|
|
"@property(nonatomic, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, assign) int p;",
|
|
"@property(assign, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, retain) int p;",
|
|
"@property(retain, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, strong) int p;",
|
|
"@property(strong, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, copy) int p;", "@property(copy, FIRST) int p;",
|
|
Style);
|
|
verifyFormat("@property(FIRST, weak) int p;", "@property(weak, FIRST) int p;",
|
|
Style);
|
|
verifyFormat("@property(FIRST, unsafe_unretained) int p;",
|
|
"@property(unsafe_unretained, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, readonly) int p;",
|
|
"@property(readonly, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, readwrite) int p;",
|
|
"@property(readwrite, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, getter) int p;",
|
|
"@property(getter, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, setter) int p;",
|
|
"@property(setter, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, nullable) int p;",
|
|
"@property(nullable, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, nonnull) int p;",
|
|
"@property(nonnull, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, null_resettable) int p;",
|
|
"@property(null_resettable, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, null_unspecified) int p;",
|
|
"@property(null_unspecified, FIRST) int p;", Style);
|
|
|
|
verifyFormat("@property(FIRST, class, LAST) int p;",
|
|
"@property(LAST, class, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, direct, LAST) int p;",
|
|
"@property(LAST, direct, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, atomic, LAST) int p;",
|
|
"@property(LAST, atomic, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, nonatomic, LAST) int p;",
|
|
"@property(LAST, nonatomic, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, assign, LAST) int p;",
|
|
"@property(LAST, assign, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, retain, LAST) int p;",
|
|
"@property(LAST, retain, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, strong, LAST) int p;",
|
|
"@property(LAST, strong, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, copy, LAST) int p;",
|
|
"@property(LAST, copy, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, weak, LAST) int p;",
|
|
"@property(LAST, weak, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, unsafe_unretained, LAST) int p;",
|
|
"@property(LAST, unsafe_unretained, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, readonly, LAST) int p;",
|
|
"@property(LAST, readonly, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, readwrite, LAST) int p;",
|
|
"@property(LAST, readwrite, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, getter, LAST) int p;",
|
|
"@property(LAST, getter, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, setter, LAST) int p;",
|
|
"@property(LAST, setter, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, nullable, LAST) int p;",
|
|
"@property(LAST, nullable, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, nonnull, LAST) int p;",
|
|
"@property(LAST, nonnull, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, null_resettable, LAST) int p;",
|
|
"@property(LAST, null_resettable, FIRST) int p;", Style);
|
|
verifyFormat("@property(FIRST, null_unspecified, LAST) int p;",
|
|
"@property(LAST, null_unspecified, FIRST) int p;", Style);
|
|
}
|
|
|
|
TEST_F(ObjCPropertyAttributeOrderFixerTest, HandlesCommentsAroundAttributes) {
|
|
FormatStyle Style = getLLVMStyle();
|
|
Style.Language = FormatStyle::LK_ObjC;
|
|
Style.ObjCPropertyAttributeOrder = {"a", "b"};
|
|
|
|
// Zero attributes but comments.
|
|
verifyFormat("@property(/* 1 */) int p;", Style);
|
|
verifyFormat("@property(/* 1 */ /* 2 */) int p;", Style);
|
|
|
|
// One attribute with comments before or after.
|
|
verifyFormat("@property(/* 1 */ a) int p;", Style);
|
|
verifyFormat("@property(a /* 2 */) int p;", Style);
|
|
verifyFormat("@property(/* 1 */ a /* 2 */) int p;", Style);
|
|
|
|
// No reordering if comments are encountered anywhere.
|
|
// (Each case represents a reordering that would have happened
|
|
// without the comment.)
|
|
verifyFormat("@property(/* before */ b, a) int p;", Style);
|
|
verifyFormat("@property(b, /* between */ a) int p;", Style);
|
|
verifyFormat("@property(b, a /* after */) int p;", Style);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace test
|
|
} // namespace format
|
|
} // namespace clang
|