[clang] cab7c52 - [CodeCompletion] Provide placeholders for known attribute arguments
Sam McCall via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 19 05:03:47 PDT 2021
Author: Sam McCall
Date: 2021-08-19T14:03:41+02:00
New Revision: cab7c52acdf508f73186dfe49b8cb012bb9129b2
URL: https://github.com/llvm/llvm-project/commit/cab7c52acdf508f73186dfe49b8cb012bb9129b2
DIFF: https://github.com/llvm/llvm-project/commit/cab7c52acdf508f73186dfe49b8cb012bb9129b2.diff
LOG: [CodeCompletion] Provide placeholders for known attribute arguments
Completion now looks more like function/member completion:
used
alias(Aliasee)
abi_tag(Tags...)
Differential Revision: https://reviews.llvm.org/D108109
Added:
Modified:
clang/include/clang/Sema/ParsedAttr.h
clang/lib/Sema/SemaCodeComplete.cpp
clang/test/CodeCompletion/attr.cpp
clang/utils/TableGen/ClangAttrEmitter.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h
index 408032cec7e8..64a078866ca5 100644
--- a/clang/include/clang/Sema/ParsedAttr.h
+++ b/clang/include/clang/Sema/ParsedAttr.h
@@ -67,6 +67,8 @@ struct ParsedAttrInfo {
const char *NormalizedFullName;
};
ArrayRef<Spelling> Spellings;
+ // The names of the known arguments of this attribute.
+ ArrayRef<const char *> ArgNames;
ParsedAttrInfo(AttributeCommonInfo::Kind AttrKind =
AttributeCommonInfo::NoSemaHandlerAttribute)
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 445ab4885cfa..8c551a798b32 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -4423,33 +4423,59 @@ void Sema::CodeCompleteAttribute(AttributeCommonInfo::Syntax Syntax,
Scope = "";
}
+ auto Add = [&](llvm::StringRef Scope, llvm::StringRef Name,
+ bool Underscores) {
+ CodeCompletionBuilder Builder(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
+ llvm::SmallString<32> Text;
+ if (!Scope.empty()) {
+ Text.append(Scope);
+ Text.append("::");
+ }
+ if (Underscores)
+ Text.append("__");
+ Text.append(Name);
+ if (Underscores)
+ Text.append("__");
+ Builder.AddTypedTextChunk(Results.getAllocator().CopyString(Text));
+
+ if (!A.ArgNames.empty()) {
+ Builder.AddChunk(CodeCompletionString::CK_LeftParen, "(");
+ bool First = true;
+ for (const char *Arg : A.ArgNames) {
+ if (!First)
+ Builder.AddChunk(CodeCompletionString::CK_Comma, ", ");
+ First = false;
+ Builder.AddPlaceholderChunk(Arg);
+ }
+ Builder.AddChunk(CodeCompletionString::CK_RightParen, ")");
+ }
+
+ Results.AddResult(Builder.TakeString());
+ };
+
// Generate the non-underscore-guarded result.
// Note this is (a suffix of) the NormalizedFullName, no need to copy.
// If an underscore-guarded scope was specified, only the
// underscore-guarded attribute name is relevant.
if (!InScopeUnderscore)
- Results.AddResult(Scope.empty() ? Name.data() : S.NormalizedFullName);
+ Add(Scope, Name, /*Underscores=*/false);
// Generate the underscore-guarded version, for syntaxes that support it.
// We skip this if the scope was already spelled and not guarded, or
// we must spell it and can't guard it.
if (!(InScope && !InScopeUnderscore) && SyntaxSupportsGuards) {
llvm::SmallString<32> Guarded;
- if (!Scope.empty()) {
+ if (Scope.empty()) {
+ Add(Scope, Name, /*Underscores=*/true);
+ } else {
const char *GuardedScope = underscoreAttrScope(Scope);
if (!GuardedScope)
continue;
- Guarded.append(GuardedScope);
- Guarded.append("::");
+ Add(GuardedScope, Name, /*Underscores=*/true);
}
- Guarded.append("__");
- Guarded.append(Name);
- Guarded.append("__");
- Results.AddResult(
- CodeCompletionResult(Results.getAllocator().CopyString(Guarded)));
}
- // FIXME: include the list of arg names (not currently exposed).
// It may be nice to include the Kind so we can look up the docs later.
}
};
diff --git a/clang/test/CodeCompletion/attr.cpp b/clang/test/CodeCompletion/attr.cpp
index 782e5a1d75ec..c3f76e7f0d99 100644
--- a/clang/test/CodeCompletion/attr.cpp
+++ b/clang/test/CodeCompletion/attr.cpp
@@ -1,81 +1,83 @@
int a [[gnu::used]];
// RUN: %clang_cc1 -code-completion-at=%s:1:9 %s | FileCheck --check-prefix=STD %s
-// STD: COMPLETION: __carries_dependency__
-// STD-NOT: COMPLETION: __convergent__
-// STD: COMPLETION: __gnu__::__used__
-// STD-NOT: COMPLETION: __gnu__::used
-// STD-NOT: COMPLETION: __used__
-// STD: COMPLETION: _Clang::__convergent__
-// STD: COMPLETION: carries_dependency
-// STD-NOT: COMPLETION: clang::called_once
-// STD: COMPLETION: clang::convergent
-// STD-NOT: COMPLETION: convergent
-// STD-NOT: COMPLETION: gnu::__used__
-// STD: COMPLETION: gnu::used
-// STD-NOT: COMPLETION: used
+// STD: COMPLETION: Pattern : __carries_dependency__
+// STD-NOT: COMPLETION: Pattern : __convergent__
+// STD: COMPLETION: Pattern : __gnu__::__used__
+// STD-NOT: COMPLETION: Pattern : __gnu__::used
+// STD-NOT: COMPLETION: Pattern : __used__
+// STD: COMPLETION: Pattern : _Clang::__convergent__
+// STD: COMPLETION: Pattern : carries_dependency
+// STD-NOT: COMPLETION: Pattern : clang::called_once
+// STD: COMPLETION: Pattern : clang::convergent
+// STD-NOT: COMPLETION: Pattern : convergent
+// STD-NOT: COMPLETION: Pattern : gnu::__used__
+// STD: COMPLETION: Pattern : gnu::abi_tag(<#Tags...#>)
+// STD: COMPLETION: Pattern : gnu::alias(<#Aliasee#>)
+// STD: COMPLETION: Pattern : gnu::used
+// STD-NOT: COMPLETION: Pattern : used
// RUN: %clang_cc1 -code-completion-at=%s:1:9 -xobjective-c++ %s | FileCheck --check-prefix=STD-OBJC %s
-// STD-OBJC: COMPLETION: clang::called_once
+// STD-OBJC: COMPLETION: Pattern : clang::called_once
// RUN: %clang_cc1 -code-completion-at=%s:1:14 %s | FileCheck --check-prefix=STD-NS %s
-// STD-NS-NOT: COMPLETION: __used__
-// STD-NS-NOT: COMPLETION: carries_dependency
-// STD-NS-NOT: COMPLETION: clang::convergent
-// STD-NS-NOT: COMPLETION: convergent
-// STD-NS-NOT: COMPLETION: gnu::used
-// STD-NS: COMPLETION: used
+// STD-NS-NOT: COMPLETION: Pattern : __used__
+// STD-NS-NOT: COMPLETION: Pattern : carries_dependency
+// STD-NS-NOT: COMPLETION: Pattern : clang::convergent
+// STD-NS-NOT: COMPLETION: Pattern : convergent
+// STD-NS-NOT: COMPLETION: Pattern : gnu::used
+// STD-NS: COMPLETION: Pattern : used
int b [[__gnu__::used]];
-// RUN: %clang_cc1 -code-completion-at=%s:25:18 %s | FileCheck --check-prefix=STD-NSU %s
-// STD-NSU: COMPLETION: __used__
-// STD-NSU-NOT: COMPLETION: used
+// RUN: %clang_cc1 -code-completion-at=%s:27:18 %s | FileCheck --check-prefix=STD-NSU %s
+// STD-NSU: COMPLETION: Pattern : __used__
+// STD-NSU-NOT: COMPLETION: Pattern : used
int c [[using gnu: used]];
-// RUN: %clang_cc1 -code-completion-at=%s:30:15 %s | FileCheck --check-prefix=STD-USING %s
+// RUN: %clang_cc1 -code-completion-at=%s:32:15 %s | FileCheck --check-prefix=STD-USING %s
// STD-USING: COMPLETION: __gnu__
// STD-USING: COMPLETION: _Clang
-// STD-USING-NOT: COMPLETION: carries_dependency
+// STD-USING-NOT: COMPLETION: Pattern : carries_dependency
// STD-USING: COMPLETION: clang
-// STD-USING-NOT: COMPLETION: clang::
-// STD-USING-NOT: COMPLETION: gnu::
+// STD-USING-NOT: COMPLETION: Pattern : clang::
+// STD-USING-NOT: COMPLETION: Pattern : gnu::
// STD-USING: COMPLETION: gnu
-// RUN: %clang_cc1 -code-completion-at=%s:30:20 %s | FileCheck --check-prefix=STD-NS %s
+// RUN: %clang_cc1 -code-completion-at=%s:32:20 %s | FileCheck --check-prefix=STD-NS %s
int d __attribute__((used));
-// RUN: %clang_cc1 -code-completion-at=%s:41:22 %s | FileCheck --check-prefix=GNU %s
-// GNU: COMPLETION: __carries_dependency__
-// GNU: COMPLETION: __convergent__
-// GNU-NOT: COMPLETION: __gnu__::__used__
-// GNU: COMPLETION: __used__
-// GNU-NOT: COMPLETION: _Clang::__convergent__
-// GNU: COMPLETION: carries_dependency
-// GNU-NOT: COMPLETION: clang::convergent
-// GNU: COMPLETION: convergent
-// GNU-NOT: COMPLETION: gnu::used
-// GNU: COMPLETION: used
+// RUN: %clang_cc1 -code-completion-at=%s:43:22 %s | FileCheck --check-prefix=GNU %s
+// GNU: COMPLETION: Pattern : __carries_dependency__
+// GNU: COMPLETION: Pattern : __convergent__
+// GNU-NOT: COMPLETION: Pattern : __gnu__::__used__
+// GNU: COMPLETION: Pattern : __used__
+// GNU-NOT: COMPLETION: Pattern : _Clang::__convergent__
+// GNU: COMPLETION: Pattern : carries_dependency
+// GNU-NOT: COMPLETION: Pattern : clang::convergent
+// GNU: COMPLETION: Pattern : convergent
+// GNU-NOT: COMPLETION: Pattern : gnu::used
+// GNU: COMPLETION: Pattern : used
#pragma clang attribute push (__attribute__((internal_linkage)), apply_to=variable)
int e;
#pragma clang attribute pop
-// RUN: %clang_cc1 -code-completion-at=%s:54:46 %s | FileCheck --check-prefix=PRAGMA %s
-// PRAGMA: internal_linkage
+// RUN: %clang_cc1 -code-completion-at=%s:56:46 %s | FileCheck --check-prefix=PRAGMA %s
+// PRAGMA: COMPLETION: Pattern : internal_linkage
#ifdef MS_EXT
int __declspec(thread) f;
-// RUN: %clang_cc1 -fms-extensions -DMS_EXT -code-completion-at=%s:61:16 %s | FileCheck --check-prefix=DS %s
-// DS-NOT: COMPLETION: __convergent__
-// DS-NOT: COMPLETION: __used__
-// DS-NOT: COMPLETION: clang::convergent
-// DS-NOT: COMPLETION: convergent
-// DS: COMPLETION: thread
-// DS-NOT: COMPLETION: used
-// DS: COMPLETION: uuid
+// RUN: %clang_cc1 -fms-extensions -DMS_EXT -code-completion-at=%s:63:16 %s | FileCheck --check-prefix=DS %s
+// DS-NOT: COMPLETION: Pattern : __convergent__
+// DS-NOT: COMPLETION: Pattern : __used__
+// DS-NOT: COMPLETION: Pattern : clang::convergent
+// DS-NOT: COMPLETION: Pattern : convergent
+// DS: COMPLETION: Pattern : thread
+// DS-NOT: COMPLETION: Pattern : used
+// DS: COMPLETION: Pattern : uuid
[uuid("123e4567-e89b-12d3-a456-426614174000")] struct g;
-// RUN: %clang_cc1 -fms-extensions -DMS_EXT -code-completion-at=%s:71:2 %s | FileCheck --check-prefix=MS %s
-// MS-NOT: COMPLETION: __uuid__
-// MS-NOT: COMPLETION: clang::convergent
-// MS-NOT: COMPLETION: convergent
-// MS-NOT: COMPLETION: thread
-// MS-NOT: COMPLETION: used
-// MS: COMPLETION: uuid
+// RUN: %clang_cc1 -fms-extensions -DMS_EXT -code-completion-at=%s:73:2 %s | FileCheck --check-prefix=MS %s
+// MS-NOT: COMPLETION: Pattern : __uuid__
+// MS-NOT: COMPLETION: Pattern : clang::convergent
+// MS-NOT: COMPLETION: Pattern : convergent
+// MS-NOT: COMPLETION: Pattern : thread
+// MS-NOT: COMPLETION: Pattern : used
+// MS: COMPLETION: Pattern : uuid
#endif // MS_EXT
void foo() {
@@ -83,9 +85,9 @@ void foo() {
{}
}
// FIXME: support for omp attributes would be nice.
-// RUN: %clang_cc1 -fopenmp -code-completion-at=%s:82:5 %s | FileCheck --check-prefix=OMP-NS --allow-empty %s
-// OMP-NS-NOT: omp
-// RUN: %clang_cc1 -fopenmp -code-completion-at=%s:82:10 %s | FileCheck --check-prefix=OMP-ATTR --allow-empty %s
-// OMP-ATTR-NOT: sequence
-// RUN: %clang_cc1 -fopenmp -code-completion-at=%s:82:19 %s | FileCheck --check-prefix=OMP-NESTED --allow-empty %s
-// OMP-NESTED-NOT: directive
+// RUN: %clang_cc1 -fopenmp -code-completion-at=%s:84:5 %s | FileCheck --check-prefix=OMP-NS --allow-empty %s
+// OMP-NS-NOT: COMPLETION: omp
+// RUN: %clang_cc1 -fopenmp -code-completion-at=%s:84:10 %s | FileCheck --check-prefix=OMP-ATTR --allow-empty %s
+// OMP-ATTR-NOT: COMPLETION: Pattern : sequence
+// RUN: %clang_cc1 -fopenmp -code-completion-at=%s:84:19 %s | FileCheck --check-prefix=OMP-NESTED --allow-empty %s
+// OMP-NESTED-NOT: COMPLETION: Pattern : directive
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index e5ac0847e108..342bbb39395f 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -3959,6 +3959,27 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
}
OS << "};\n";
}
+
+ std::vector<std::string> ArgNames;
+ for (const auto &Arg : Attr.getValueAsListOfDefs("Args")) {
+ bool UnusedUnset;
+ if (Arg->getValueAsBitOrUnset("Fake", UnusedUnset))
+ continue;
+ ArgNames.push_back(Arg->getValueAsString("Name").str());
+ for (const auto &Class : Arg->getSuperClasses()) {
+ if (Class.first->getName().startswith("Variadic")) {
+ ArgNames.back().append("...");
+ break;
+ }
+ }
+ }
+ if (!ArgNames.empty()) {
+ OS << "static constexpr const char *" << I->first << "ArgNames[] = {\n";
+ for (const auto &N : ArgNames)
+ OS << '"' << N << "\",";
+ OS << "};\n";
+ }
+
OS << "struct ParsedAttrInfo" << I->first
<< " final : public ParsedAttrInfo {\n";
OS << " ParsedAttrInfo" << I->first << "() {\n";
@@ -3980,6 +4001,8 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
OS << PragmaAttributeSupport.isAttributedSupported(*I->second) << ";\n";
if (!Spellings.empty())
OS << " Spellings = " << I->first << "Spellings;\n";
+ if (!ArgNames.empty())
+ OS << " ArgNames = " << I->first << "ArgNames;\n";
OS << " }\n";
GenerateAppertainsTo(Attr, OS);
GenerateMutualExclusionsChecks(Attr, Records, OS, MergeDeclOS, MergeStmtOS);
More information about the cfe-commits
mailing list