Skip to content

Commit 3c33deb

Browse files
committed
[CodeCompletion] Make all result's string fields null terminated
This is convenient for clients to pass these fields values to C functions. Introduce NullTerminatedStringRef to guarantee that.
1 parent 7ef93b2 commit 3c33deb

File tree

8 files changed

+155
-88
lines changed

8 files changed

+155
-88
lines changed

include/swift/Basic/StringExtras.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,52 @@ bool omitNeedlessWords(StringRef &baseName,
469469
/// If the name has a completion-handler suffix, strip off that suffix.
470470
Optional<StringRef> stripWithCompletionHandlerSuffix(StringRef name);
471471

472+
/// Represents a string that can be efficiently retrieved either as a StringRef
473+
/// or as a null-terminated C string.
474+
class NullTerminatedStringRef {
475+
StringRef Ref;
476+
477+
public:
478+
/// Create a \c NullTerminatedStringRef from a null-terminated C string with
479+
/// size \p Size (excluding the null character).
480+
NullTerminatedStringRef(const char *Data, size_t Size) : Ref(Data, Size) {
481+
assert(Data != nullptr && Data[Size] == '\0' &&
482+
"Data should be null-terminated");
483+
}
484+
485+
/// Create an empty null-terminated string. \c data() is not a \c nullptr.
486+
constexpr NullTerminatedStringRef() : Ref("") {}
487+
488+
/// Create an null terminated string with a C string.
489+
constexpr NullTerminatedStringRef(const char *Data) : Ref(Data) {}
490+
491+
/// Create a null-terminated string, copying \p Str into \p A .
492+
template <typename Allocator>
493+
NullTerminatedStringRef(StringRef Str, Allocator &A) : Ref("") {
494+
if (Str.empty())
495+
return;
496+
497+
size_t size = Str.size();
498+
char *memory = A.template Allocate<char>(size + 1);
499+
memcpy(memory, Str.data(), size);
500+
memory[size] = '\0';
501+
Ref = {memory, size};
502+
}
503+
504+
/// Returns the string as a `StringRef`. The `StringRef` does not include the
505+
/// null character.
506+
operator StringRef() const { return Ref; }
507+
508+
/// Returns the string as a null-terminated C string.
509+
const char *data() const { return Ref.data(); }
510+
511+
/// The size of the string, excluding the null character.
512+
size_t size() const { return Ref.size(); }
513+
514+
bool empty() const { return Ref.empty(); }
515+
int compare(NullTerminatedStringRef RHS) const { return Ref.compare(RHS); }
516+
};
517+
472518
} // end namespace swift
473519

474520
#endif // SWIFT_BASIC_STRINGEXTRAS_H

include/swift/IDE/CodeCompletion.h

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "swift/Basic/Debug.h"
1919
#include "swift/Basic/LLVM.h"
2020
#include "swift/Basic/OptionSet.h"
21+
#include "swift/Basic/StringExtras.h"
2122
#include "swift/Frontend/Frontend.h"
2223
#include "llvm/ADT/ArrayRef.h"
2324
#include "llvm/ADT/StringMap.h"
@@ -717,9 +718,9 @@ class ContextFreeCodeCompletionResult {
717718

718719
bool IsSystem : 1;
719720
CodeCompletionString *CompletionString;
720-
StringRef ModuleName;
721-
StringRef BriefDocComment;
722-
ArrayRef<StringRef> AssociatedUSRs;
721+
NullTerminatedStringRef ModuleName;
722+
NullTerminatedStringRef BriefDocComment;
723+
ArrayRef<NullTerminatedStringRef> AssociatedUSRs;
723724
CodeCompletionResultType ResultType;
724725

725726
ContextFreeNotRecommendedReason NotRecommended : 3;
@@ -728,8 +729,8 @@ class ContextFreeCodeCompletionResult {
728729
CodeCompletionDiagnosticSeverity DiagnosticSeverity : 3;
729730
static_assert(int(CodeCompletionDiagnosticSeverity::MAX_VALUE) < 1 << 3, "");
730731

731-
StringRef DiagnosticMessage;
732-
StringRef FilterName;
732+
NullTerminatedStringRef DiagnosticMessage;
733+
NullTerminatedStringRef FilterName;
733734

734735
public:
735736
/// Memberwise initializer. \p AssociatedKInd is opaque and will be
@@ -743,12 +744,15 @@ class ContextFreeCodeCompletionResult {
743744
ContextFreeCodeCompletionResult(
744745
CodeCompletionResultKind Kind, uint8_t AssociatedKind,
745746
CodeCompletionOperatorKind KnownOperatorKind, bool IsSystem,
746-
CodeCompletionString *CompletionString, StringRef ModuleName,
747-
StringRef BriefDocComment, ArrayRef<StringRef> AssociatedUSRs,
747+
CodeCompletionString *CompletionString,
748+
NullTerminatedStringRef ModuleName,
749+
NullTerminatedStringRef BriefDocComment,
750+
ArrayRef<NullTerminatedStringRef> AssociatedUSRs,
748751
CodeCompletionResultType ResultType,
749752
ContextFreeNotRecommendedReason NotRecommended,
750753
CodeCompletionDiagnosticSeverity DiagnosticSeverity,
751-
StringRef DiagnosticMessage, StringRef FilterName)
754+
NullTerminatedStringRef DiagnosticMessage,
755+
NullTerminatedStringRef FilterName)
752756
: Kind(Kind), KnownOperatorKind(KnownOperatorKind), IsSystem(IsSystem),
753757
CompletionString(CompletionString), ModuleName(ModuleName),
754758
BriefDocComment(BriefDocComment), AssociatedUSRs(AssociatedUSRs),
@@ -780,21 +784,24 @@ class ContextFreeCodeCompletionResult {
780784
static ContextFreeCodeCompletionResult *createPatternOrBuiltInOperatorResult(
781785
llvm::BumpPtrAllocator &Allocator, CodeCompletionResultKind Kind,
782786
CodeCompletionString *CompletionString,
783-
CodeCompletionOperatorKind KnownOperatorKind, StringRef BriefDocComment,
787+
CodeCompletionOperatorKind KnownOperatorKind,
788+
NullTerminatedStringRef BriefDocComment,
784789
CodeCompletionResultType ResultType,
785790
ContextFreeNotRecommendedReason NotRecommended,
786791
CodeCompletionDiagnosticSeverity DiagnosticSeverity,
787-
StringRef DiagnosticMessage);
792+
NullTerminatedStringRef DiagnosticMessage);
788793

789794
/// Constructs a \c Keyword result.
790795
///
791796
/// \note The caller must ensure that the \p CompletionString and
792797
/// \p BriefDocComment outlive this result, typically by storing them in
793798
/// the same \c CodeCompletionResultSink as the result itself.
794-
static ContextFreeCodeCompletionResult *createKeywordResult(
795-
llvm::BumpPtrAllocator &Allocator, CodeCompletionKeywordKind Kind,
796-
CodeCompletionString *CompletionString, StringRef BriefDocComment,
797-
CodeCompletionResultType ResultType);
799+
static ContextFreeCodeCompletionResult *
800+
createKeywordResult(llvm::BumpPtrAllocator &Allocator,
801+
CodeCompletionKeywordKind Kind,
802+
CodeCompletionString *CompletionString,
803+
NullTerminatedStringRef BriefDocComment,
804+
CodeCompletionResultType ResultType);
798805

799806
/// Constructs a \c Literal result.
800807
///
@@ -814,12 +821,13 @@ class ContextFreeCodeCompletionResult {
814821
/// \c CodeCompletionResultSink as the result itself.
815822
static ContextFreeCodeCompletionResult *createDeclResult(
816823
llvm::BumpPtrAllocator &Allocator, CodeCompletionString *CompletionString,
817-
const Decl *AssociatedDecl, StringRef ModuleName,
818-
StringRef BriefDocComment, ArrayRef<StringRef> AssociatedUSRs,
824+
const Decl *AssociatedDecl, NullTerminatedStringRef ModuleName,
825+
NullTerminatedStringRef BriefDocComment,
826+
ArrayRef<NullTerminatedStringRef> AssociatedUSRs,
819827
CodeCompletionResultType ResultType,
820828
ContextFreeNotRecommendedReason NotRecommended,
821829
CodeCompletionDiagnosticSeverity DiagnosticSeverity,
822-
StringRef DiagnosticMessage);
830+
NullTerminatedStringRef DiagnosticMessage);
823831

824832
CodeCompletionResultKind getKind() const { return Kind; }
825833

@@ -849,11 +857,13 @@ class ContextFreeCodeCompletionResult {
849857

850858
CodeCompletionString *getCompletionString() const { return CompletionString; }
851859

852-
StringRef getModuleName() const { return ModuleName; }
860+
NullTerminatedStringRef getModuleName() const { return ModuleName; }
853861

854-
StringRef getBriefDocComment() const { return BriefDocComment; }
862+
NullTerminatedStringRef getBriefDocComment() const { return BriefDocComment; }
855863

856-
ArrayRef<StringRef> getAssociatedUSRs() const { return AssociatedUSRs; }
864+
ArrayRef<NullTerminatedStringRef> getAssociatedUSRs() const {
865+
return AssociatedUSRs;
866+
}
857867

858868
const CodeCompletionResultType &getResultType() const { return ResultType; }
859869

@@ -864,9 +874,11 @@ class ContextFreeCodeCompletionResult {
864874
CodeCompletionDiagnosticSeverity getDiagnosticSeverity() const {
865875
return DiagnosticSeverity;
866876
}
867-
StringRef getDiagnosticMessage() const { return DiagnosticMessage; }
877+
NullTerminatedStringRef getDiagnosticMessage() const {
878+
return DiagnosticMessage;
879+
}
868880

869-
StringRef getFilterName() const { return FilterName; }
881+
NullTerminatedStringRef getFilterName() const { return FilterName; }
870882

871883
bool isOperator() const {
872884
if (getKind() == CodeCompletionResultKind::Declaration) {
@@ -908,7 +920,7 @@ class CodeCompletionResult {
908920
CodeCompletionDiagnosticSeverity DiagnosticSeverity : 3;
909921
static_assert(int(CodeCompletionDiagnosticSeverity::MAX_VALUE) < 1 << 3, "");
910922

911-
StringRef DiagnosticMessage;
923+
NullTerminatedStringRef DiagnosticMessage;
912924

913925
/// The number of bytes to the left of the code completion point that
914926
/// should be erased first if this completion string is inserted in the
@@ -932,7 +944,7 @@ class CodeCompletionResult {
932944
CodeCompletionResultTypeRelation TypeDistance,
933945
ContextualNotRecommendedReason NotRecommended,
934946
CodeCompletionDiagnosticSeverity DiagnosticSeverity,
935-
StringRef DiagnosticMessage)
947+
NullTerminatedStringRef DiagnosticMessage)
936948
: ContextFree(ContextFree), SemanticContext(SemanticContext),
937949
Flair(Flair.toRaw()), NotRecommended(NotRecommended),
938950
DiagnosticSeverity(DiagnosticSeverity),
@@ -954,7 +966,7 @@ class CodeCompletionResult {
954966
const DeclContext *DC,
955967
ContextualNotRecommendedReason NotRecommended,
956968
CodeCompletionDiagnosticSeverity DiagnosticSeverity,
957-
StringRef DiagnosticMessage);
969+
NullTerminatedStringRef DiagnosticMessage);
958970

959971
const ContextFreeCodeCompletionResult &getContextFreeResult() const {
960972
return ContextFree;
@@ -1063,15 +1075,15 @@ class CodeCompletionResult {
10631075
return getContextFreeResult().getCompletionString();
10641076
}
10651077

1066-
StringRef getModuleName() const {
1078+
NullTerminatedStringRef getModuleName() const {
10671079
return getContextFreeResult().getModuleName();
10681080
}
10691081

1070-
StringRef getBriefDocComment() const {
1082+
NullTerminatedStringRef getBriefDocComment() const {
10711083
return getContextFreeResult().getBriefDocComment();
10721084
}
10731085

1074-
ArrayRef<StringRef> getAssociatedUSRs() const {
1086+
ArrayRef<NullTerminatedStringRef> getAssociatedUSRs() const {
10751087
return getContextFreeResult().getAssociatedUSRs();
10761088
}
10771089

@@ -1083,7 +1095,9 @@ class CodeCompletionResult {
10831095

10841096
/// Get the contextual diagnostic message. This disregards context-free
10851097
/// diagnostics.
1086-
StringRef getContextualDiagnosticMessage() const { return DiagnosticMessage; }
1098+
NullTerminatedStringRef getContextualDiagnosticMessage() const {
1099+
return DiagnosticMessage;
1100+
}
10871101

10881102
/// Return the contextual diagnostic severity if there was a contextual
10891103
/// diagnostic. If there is no contextual diagnostic, return the context-free
@@ -1099,15 +1113,15 @@ class CodeCompletionResult {
10991113
/// Return the contextual diagnostic message if there was a contextual
11001114
/// diagnostic. If there is no contextual diagnostic, return the context-free
11011115
/// diagnostic message.
1102-
StringRef getDiagnosticMessage() const {
1116+
NullTerminatedStringRef getDiagnosticMessage() const {
11031117
if (NotRecommended != ContextualNotRecommendedReason::None) {
11041118
return DiagnosticMessage;
11051119
} else {
11061120
return getContextFreeResult().getDiagnosticMessage();
11071121
}
11081122
}
11091123

1110-
StringRef getFilterName() const {
1124+
NullTerminatedStringRef getFilterName() const {
11111125
return getContextFreeResult().getFilterName();
11121126
}
11131127

@@ -1146,7 +1160,7 @@ struct CodeCompletionResultSink {
11461160

11471161
/// A single-element cache for module names stored in Allocator, keyed by a
11481162
/// clang::Module * or swift::ModuleDecl *.
1149-
std::pair<void *, StringRef> LastModule;
1163+
std::pair<void *, NullTerminatedStringRef> LastModule;
11501164

11511165
CodeCompletionResultSink()
11521166
: Allocator(std::make_shared<llvm::BumpPtrAllocator>()) {}

include/swift/IDE/CodeCompletionResultPrinter.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
#include "llvm/Support/Allocator.h"
1919

2020
namespace swift {
21+
22+
class NullTerminatedStringRef;
23+
2124
namespace ide {
2225

2326
class CodeCompletionResult;
@@ -41,9 +44,10 @@ void printCodeCompletionResultSourceText(
4144
const CodeCompletionResult &Result, llvm::raw_ostream &OS);
4245

4346
/// Print 'FilterName' from \p str into memory managed by \p Allocator and
44-
/// return it.
45-
llvm::StringRef getCodeCompletionResultFilterName(
46-
const CodeCompletionString *Str, llvm::BumpPtrAllocator &Allocator);
47+
/// return it as \c NullTerminatedStringRef .
48+
NullTerminatedStringRef
49+
getCodeCompletionResultFilterName(const CodeCompletionString *Str,
50+
llvm::BumpPtrAllocator &Allocator);
4751

4852
} // namespace ide
4953
} // namespace swift

0 commit comments

Comments
 (0)