Skip to content

Commit

Permalink
Merge pull request swiftlang#34095 from Interfere/SR-13490-fix-compar…
Browse files Browse the repository at this point in the history
…eImports
  • Loading branch information
swift-ci committed Sep 30, 2020
2 parents 5e399b9 + 8615904 commit 8857deb
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 28 deletions.
19 changes: 17 additions & 2 deletions include/swift/AST/Import.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@
#include "swift/AST/Identifier.h"
#include "swift/Basic/Located.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include <algorithm>

namespace swift {
class ASTContext;
Expand Down Expand Up @@ -191,6 +192,20 @@ namespace detail {
};
}

/// @name ImportPathBase Comparison Operators
/// @{
template <typename Subclass>
inline bool operator<(const detail::ImportPathBase<Subclass> &LHS,
const detail::ImportPathBase<Subclass> &RHS) {
using Element = typename detail::ImportPathBase<Subclass>::Element;
auto Comparator = [](const Element &l, const Element &r) {
return l.Item.compare(r.Item) < 0;
};
return std::lexicographical_compare(LHS.begin(), LHS.end(), RHS.begin(),
RHS.end(), Comparator);
}
/// @}

/// An undifferentiated series of dotted identifiers in an \c import statement,
/// like \c Foo.Bar. Each identifier is packaged with its corresponding source
/// location.
Expand Down
10 changes: 1 addition & 9 deletions lib/IDE/ModuleInterfacePrinting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,15 +374,7 @@ static bool printModuleInterfaceDecl(Decl *D,

/// Sorts import declarations for display.
static bool compareImports(ImportDecl *LHS, ImportDecl *RHS) {
// TODO(SR-13490): Probably buggy--thinks "import Foo" == "import Foo.Bar".
// ImportPathBase should provide universal comparison functions to avoid this.
auto LHSPath = LHS->getImportPath();
auto RHSPath = RHS->getImportPath();
for (unsigned i: range(std::min(LHSPath.size(), RHSPath.size()))) {
if (int Ret = LHSPath[i].Item.str().compare(RHSPath[i].Item.str()))
return Ret < 0;
}
return false;
return LHS->getImportPath() < RHS->getImportPath();
};

/// Sorts Swift declarations for display.
Expand Down
2 changes: 1 addition & 1 deletion test/IDE/print_ast_overlay.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@ public class FooOverlayClassDerived : FooOverlayClassBase {

// PASS_NO_INTERNAL-NOT: overlay_func_internal

// PASS_ANNOTATED: <decl:Import>@_exported import <ref:module>Foo</ref>.<ref:module>FooSub</ref></decl>
// PASS_ANNOTATED: <decl:Import>@_exported import <ref:module>Foo</ref></decl>
// PASS_ANNOTATED: <decl:Import>@_exported import <ref:module>Foo</ref>.<ref:module>FooSub</ref></decl>
// PASS_ANNOTATED: <decl:Import>@_exported import <ref:module>FooHelper</ref></decl>
12 changes: 6 additions & 6 deletions test/SourceKit/InterfaceGen/gen_clang_module.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,21 +73,21 @@ var x: FooClassBase

// RUN: %sourcekitd-test -req=interface-gen-open -module Foo -- -I %t.overlays -F %S/../Inputs/libIDE-mock-sdk \
// RUN: -target %target-triple %clang-importer-sdk-nosource -I %t \
// RUN: == -req=cursor -pos=1:8 == -req=cursor -pos=1:12 \
// RUN: == -req=cursor -pos=2:10 \
// RUN: == -req=cursor -pos=3:10 | %FileCheck -check-prefix=CHECK-IMPORT %s
// RUN: == -req=cursor -pos=1:8 \
// RUN: == -req=cursor -pos=2:8 == -req=cursor -pos=2:12 \
// RUN: == -req=cursor -pos=3:8 | %FileCheck -check-prefix=CHECK-IMPORT %s
// The cursors point to module names inside the imports, see 'gen_clang_module.swift.response'

// CHECK-IMPORT: source.lang.swift.ref.module ()
// CHECK-IMPORT-NEXT: Foo{{$}}
// CHECK-IMPORT-NEXT: Foo{{$}}
// CHECK-IMPORT: source.lang.swift.ref.module ()
// CHECK-IMPORT-NEXT: FooSub{{$}}
// CHECK-IMPORT-NEXT: Foo.FooSub{{$}}
// CHECK-IMPORT: source.lang.swift.ref.module ()
// CHECK-IMPORT-NEXT: Foo{{$}}
// CHECK-IMPORT-NEXT: Foo{{$}}
// CHECK-IMPORT: source.lang.swift.ref.module ()
// CHECK-IMPORT-NEXT: FooSub{{$}}
// CHECK-IMPORT-NEXT: Foo.FooSub{{$}}
// CHECK-IMPORT: source.lang.swift.ref.module ()
// CHECK-IMPORT-NEXT: FooHelper{{$}}
// CHECK-IMPORT-NEXT: FooHelper{{$}}

Expand Down
20 changes: 10 additions & 10 deletions test/SourceKit/InterfaceGen/gen_clang_module.swift.response
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Foo.FooSub
import Foo
import Foo.FooSub
import FooHelper
import SwiftOnoneSupport

Expand Down Expand Up @@ -370,19 +370,19 @@ public class FooOverlayClassDerived : Foo.FooOverlayClassBase {
key.length: 3
},
{
key.kind: source.lang.swift.syntaxtype.identifier,
key.kind: source.lang.swift.syntaxtype.keyword,
key.offset: 11,
key.length: 6
},
{
key.kind: source.lang.swift.syntaxtype.keyword,
key.kind: source.lang.swift.syntaxtype.identifier,
key.offset: 18,
key.length: 6
key.length: 3
},
{
key.kind: source.lang.swift.syntaxtype.identifier,
key.offset: 25,
key.length: 3
key.offset: 22,
key.length: 6
},
{
key.kind: source.lang.swift.syntaxtype.keyword,
Expand Down Expand Up @@ -3608,13 +3608,13 @@ public class FooOverlayClassDerived : Foo.FooOverlayClassBase {
},
{
key.kind: source.lang.swift.ref.module,
key.offset: 11,
key.length: 6
key.offset: 18,
key.length: 3
},
{
key.kind: source.lang.swift.ref.module,
key.offset: 25,
key.length: 3
key.offset: 22,
key.length: 6
},
{
key.kind: source.lang.swift.ref.module,
Expand Down
1 change: 1 addition & 0 deletions unittests/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ add_swift_unittest(SwiftASTTests
TestContext.cpp
TypeMatchTests.cpp
VersionRangeLattice.cpp
ImportTests.cpp
)

target_link_libraries(SwiftASTTests
Expand Down
60 changes: 60 additions & 0 deletions unittests/AST/ImportTests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//===--- ImportTests.cpp - Tests for representation of imports ------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "TestContext.h"
#include "swift/AST/Import.h"
#include "gtest/gtest.h"

using namespace swift;
using namespace swift::unittest;

namespace {
/// Helper class used to create ImportPath and hold all strings for identifiers
class ImportPathContext {
TestContext Ctx;

public:
ImportPathContext() = default;

/// Hepler routine for building ImportPath
/// Build()
/// @see ImportPathBuilder
inline ImportPath Build(StringRef Name) noexcept {
return ImportPath::Builder(Ctx.Ctx, Name, '.').copyTo(Ctx.Ctx);
}
};

} // namespace

TEST(ImportPath, Comparison) {
ImportPathContext ctx;

/// Simple sanity check:
EXPECT_FALSE(ctx.Build("A.B.C") < ctx.Build("A.B.C"));

/// Check order chain:
/// A < A.A < A.A.A < A.A.B < A.B < A.B.A < AA < B < B.A
EXPECT_LT(ctx.Build("A"), ctx.Build("A.A"));
EXPECT_LT(ctx.Build("A.A"), ctx.Build("A.A.A"));
EXPECT_LT(ctx.Build("A.A.A"), ctx.Build("A.A.B"));
EXPECT_LT(ctx.Build("A.A.B"), ctx.Build("A.B"));
EXPECT_LT(ctx.Build("A.B"), ctx.Build("A.B.A"));
EXPECT_LT(ctx.Build("A.B.A"), ctx.Build("AA"));
EXPECT_LT(ctx.Build("B"), ctx.Build("B.A"));

/// Further ImportPaths are semantically incorrect, but we must
/// check that comparing them does not cause compiler to crash.
EXPECT_LT(ctx.Build("."), ctx.Build("A"));
EXPECT_LT(ctx.Build("A"), ctx.Build("AA."));
EXPECT_LT(ctx.Build("A"), ctx.Build("AA.."));
EXPECT_LT(ctx.Build(".A"), ctx.Build("AA"));
}

0 comments on commit 8857deb

Please sign in to comment.