forked from OSchip/llvm-project
[CodeComplete] Basic code completion for attribute names.
Only the bare name is completed, with no args. For args to be useful we need arg names. These *are* in the tablegen but not currently emitted in usable form, so left this as future work. C++11, C2x, GNU, declspec, MS syntax is supported, with the appropriate spellings of attributes suggested. `#pragma clang attribute` is supported but not terribly useful as we only reach completion if parens are balanced (i.e. the line is not truncated) There's no filtering of which attributes might make sense in this grammatical context (e.g. attached to a function). In code-completion context this is hard to do, and will only work in few cases :-( There's also no filtering by langopts: this is because currently the only way of checking is to try to produce diagnostics, which requires a valid ParsedAttr which is hard to get. This should be fairly simple to fix but requires some tablegen changes to expose the logic without the side-effect. Differential Revision: https://reviews.llvm.org/D107696
This commit is contained in:
parent
3b99acbff2
commit
ece4e92085
|
@ -715,6 +715,7 @@ bool contextAllowsIndex(enum CodeCompletionContext::Kind K) {
|
|||
case CodeCompletionContext::CCC_ObjCInstanceMessage:
|
||||
case CodeCompletionContext::CCC_ObjCClassMessage:
|
||||
case CodeCompletionContext::CCC_IncludedFile:
|
||||
case CodeCompletionContext::CCC_Attribute:
|
||||
// FIXME: Provide identifier based completions for the following contexts:
|
||||
case CodeCompletionContext::CCC_Other: // Be conservative.
|
||||
case CodeCompletionContext::CCC_NaturalLanguage:
|
||||
|
|
|
@ -2834,7 +2834,10 @@ private:
|
|||
SourceLocation ScopeLoc,
|
||||
CachedTokens &OpenMPTokens);
|
||||
|
||||
IdentifierInfo *TryParseCXX11AttributeIdentifier(SourceLocation &Loc);
|
||||
IdentifierInfo *TryParseCXX11AttributeIdentifier(
|
||||
SourceLocation &Loc,
|
||||
Sema::AttributeCompletion Completion = Sema::AttributeCompletion::None,
|
||||
const IdentifierInfo *EnclosingScope = nullptr);
|
||||
|
||||
void MaybeParseMicrosoftAttributes(ParsedAttributes &attrs,
|
||||
SourceLocation *endLoc = nullptr) {
|
||||
|
|
|
@ -329,6 +329,9 @@ public:
|
|||
/// Code completion inside the filename part of a #include directive.
|
||||
CCC_IncludedFile,
|
||||
|
||||
/// Code completion of an attribute name.
|
||||
CCC_Attribute,
|
||||
|
||||
/// An unknown context, in which we are recovering from a parsing
|
||||
/// error and don't know which completions we should give.
|
||||
CCC_Recovery
|
||||
|
|
|
@ -123,6 +123,7 @@ struct ParsedAttrInfo {
|
|||
}
|
||||
|
||||
static const ParsedAttrInfo &get(const AttributeCommonInfo &A);
|
||||
static ArrayRef<const ParsedAttrInfo *> getAllBuiltin();
|
||||
};
|
||||
|
||||
typedef llvm::Registry<ParsedAttrInfo> ParsedAttrInfoRegistry;
|
||||
|
|
|
@ -12377,6 +12377,15 @@ public:
|
|||
const VirtSpecifiers *VS = nullptr);
|
||||
void CodeCompleteBracketDeclarator(Scope *S);
|
||||
void CodeCompleteCase(Scope *S);
|
||||
enum class AttributeCompletion {
|
||||
Attribute,
|
||||
Scope,
|
||||
None,
|
||||
};
|
||||
void CodeCompleteAttribute(
|
||||
AttributeCommonInfo::Syntax Syntax,
|
||||
AttributeCompletion Completion = AttributeCompletion::Attribute,
|
||||
const IdentifierInfo *Scope = nullptr);
|
||||
/// Determines the preferred type of the current function argument, by
|
||||
/// examining the signatures of all possible overloads.
|
||||
/// Returns null if unknown or ambiguous, or if code completion is off.
|
||||
|
|
|
@ -1989,6 +1989,7 @@ static void CalculateHiddenNames(const CodeCompletionContext &Context,
|
|||
case CodeCompletionContext::CCC_ObjCClassMessage:
|
||||
case CodeCompletionContext::CCC_ObjCCategoryName:
|
||||
case CodeCompletionContext::CCC_IncludedFile:
|
||||
case CodeCompletionContext::CCC_Attribute:
|
||||
case CodeCompletionContext::CCC_NewName:
|
||||
// We're looking for nothing, or we're looking for names that cannot
|
||||
// be hidden.
|
||||
|
|
|
@ -195,6 +195,11 @@ void Parser::ParseGNUAttributes(ParsedAttributesWithRange &Attrs,
|
|||
// Expect an identifier or declaration specifier (const, int, etc.)
|
||||
if (Tok.isAnnotation())
|
||||
break;
|
||||
if (Tok.is(tok::code_completion)) {
|
||||
cutOffParsing();
|
||||
Actions.CodeCompleteAttribute(AttributeCommonInfo::Syntax::AS_GNU);
|
||||
break;
|
||||
}
|
||||
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
|
||||
if (!AttrName)
|
||||
break;
|
||||
|
@ -714,6 +719,12 @@ void Parser::ParseMicrosoftDeclSpecs(ParsedAttributes &Attrs,
|
|||
if (TryConsumeToken(tok::comma))
|
||||
continue;
|
||||
|
||||
if (Tok.is(tok::code_completion)) {
|
||||
cutOffParsing();
|
||||
Actions.CodeCompleteAttribute(AttributeCommonInfo::AS_Declspec);
|
||||
return;
|
||||
}
|
||||
|
||||
// We expect either a well-known identifier or a generic string. Anything
|
||||
// else is a malformed declspec.
|
||||
bool IsString = Tok.getKind() == tok::string_literal;
|
||||
|
|
|
@ -4105,7 +4105,10 @@ void Parser::PopParsingClass(Sema::ParsingClassState state) {
|
|||
/// If a keyword or an alternative token that satisfies the syntactic
|
||||
/// requirements of an identifier is contained in an attribute-token,
|
||||
/// it is considered an identifier.
|
||||
IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) {
|
||||
IdentifierInfo *
|
||||
Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc,
|
||||
Sema::AttributeCompletion Completion,
|
||||
const IdentifierInfo *Scope) {
|
||||
switch (Tok.getKind()) {
|
||||
default:
|
||||
// Identifiers and keywords have identifier info attached.
|
||||
|
@ -4117,6 +4120,13 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) {
|
|||
}
|
||||
return nullptr;
|
||||
|
||||
case tok::code_completion:
|
||||
cutOffParsing();
|
||||
Actions.CodeCompleteAttribute(getLangOpts().CPlusPlus ? ParsedAttr::AS_CXX11
|
||||
: ParsedAttr::AS_C2x,
|
||||
Completion, Scope);
|
||||
return nullptr;
|
||||
|
||||
case tok::numeric_constant: {
|
||||
// If we got a numeric constant, check to see if it comes from a macro that
|
||||
// corresponds to the predefined __clang__ macro. If it does, warn the user
|
||||
|
@ -4392,7 +4402,8 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs,
|
|||
: diag::ext_using_attribute_ns);
|
||||
ConsumeToken();
|
||||
|
||||
CommonScopeName = TryParseCXX11AttributeIdentifier(CommonScopeLoc);
|
||||
CommonScopeName = TryParseCXX11AttributeIdentifier(
|
||||
CommonScopeLoc, Sema::AttributeCompletion::Scope);
|
||||
if (!CommonScopeName) {
|
||||
Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
|
||||
SkipUntil(tok::r_square, tok::colon, StopBeforeMatch);
|
||||
|
@ -4422,7 +4433,8 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs,
|
|||
SourceLocation ScopeLoc, AttrLoc;
|
||||
IdentifierInfo *ScopeName = nullptr, *AttrName = nullptr;
|
||||
|
||||
AttrName = TryParseCXX11AttributeIdentifier(AttrLoc);
|
||||
AttrName = TryParseCXX11AttributeIdentifier(
|
||||
AttrLoc, Sema::AttributeCompletion::Attribute, CommonScopeName);
|
||||
if (!AttrName)
|
||||
// Break out to the "expected ']'" diagnostic.
|
||||
break;
|
||||
|
@ -4432,7 +4444,8 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs,
|
|||
ScopeName = AttrName;
|
||||
ScopeLoc = AttrLoc;
|
||||
|
||||
AttrName = TryParseCXX11AttributeIdentifier(AttrLoc);
|
||||
AttrName = TryParseCXX11AttributeIdentifier(
|
||||
AttrLoc, Sema::AttributeCompletion::Attribute, ScopeName);
|
||||
if (!AttrName) {
|
||||
Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
|
||||
SkipUntil(tok::r_square, tok::comma, StopAtSemi | StopBeforeMatch);
|
||||
|
@ -4647,7 +4660,15 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs,
|
|||
|
||||
// Skip most ms attributes except for a specific list.
|
||||
while (true) {
|
||||
SkipUntil(tok::r_square, tok::identifier, StopAtSemi | StopBeforeMatch);
|
||||
SkipUntil(tok::r_square, tok::identifier,
|
||||
StopAtSemi | StopBeforeMatch | StopAtCodeCompletion);
|
||||
if (Tok.is(tok::code_completion)) {
|
||||
cutOffParsing();
|
||||
Actions.CodeCompleteAttribute(AttributeCommonInfo::AS_Microsoft,
|
||||
Sema::AttributeCompletion::Attribute,
|
||||
/*Scope=*/nullptr);
|
||||
break;
|
||||
}
|
||||
if (Tok.isNot(tok::identifier)) // ']', but also eof
|
||||
break;
|
||||
if (Tok.getIdentifierInfo()->getName() == "uuid")
|
||||
|
|
|
@ -1592,6 +1592,15 @@ void Parser::HandlePragmaAttribute() {
|
|||
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "("))
|
||||
return SkipToEnd();
|
||||
|
||||
// FIXME: The practical usefulness of completion here is limited because
|
||||
// we only get here if the line has balanced parens.
|
||||
if (Tok.is(tok::code_completion)) {
|
||||
cutOffParsing();
|
||||
// FIXME: suppress completion of unsupported attributes?
|
||||
Actions.CodeCompleteAttribute(AttributeCommonInfo::Syntax::AS_GNU);
|
||||
return SkipToEnd();
|
||||
}
|
||||
|
||||
if (Tok.isNot(tok::identifier)) {
|
||||
Diag(Tok, diag::err_pragma_attribute_expected_attribute_name);
|
||||
SkipToEnd();
|
||||
|
|
|
@ -82,6 +82,7 @@ bool CodeCompletionContext::wantConstructorResults() const {
|
|||
case CCC_ObjCInterfaceName:
|
||||
case CCC_ObjCCategoryName:
|
||||
case CCC_IncludedFile:
|
||||
case CCC_Attribute:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -161,6 +162,8 @@ StringRef clang::getCompletionKindString(CodeCompletionContext::Kind Kind) {
|
|||
return "ObjCCategoryName";
|
||||
case CCKind::CCC_IncludedFile:
|
||||
return "IncludedFile";
|
||||
case CCKind::CCC_Attribute:
|
||||
return "Attribute";
|
||||
case CCKind::CCC_Recovery:
|
||||
return "Recovery";
|
||||
}
|
||||
|
|
|
@ -145,6 +145,10 @@ const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) {
|
|||
return DefaultParsedAttrInfo;
|
||||
}
|
||||
|
||||
ArrayRef<const ParsedAttrInfo *> ParsedAttrInfo::getAllBuiltin() {
|
||||
return AttrInfoMap;
|
||||
}
|
||||
|
||||
unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; }
|
||||
|
||||
unsigned ParsedAttr::getMaxArgs() const {
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "clang/AST/QualTypeNames.h"
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/AttributeCommonInfo.h"
|
||||
#include "clang/Basic/CharInfo.h"
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
|
@ -34,6 +35,7 @@
|
|||
#include "clang/Sema/Designator.h"
|
||||
#include "clang/Sema/Lookup.h"
|
||||
#include "clang/Sema/Overload.h"
|
||||
#include "clang/Sema/ParsedAttr.h"
|
||||
#include "clang/Sema/Scope.h"
|
||||
#include "clang/Sema/ScopeInfo.h"
|
||||
#include "clang/Sema/Sema.h"
|
||||
|
@ -4335,6 +4337,131 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS,
|
|||
Results.data(), Results.size());
|
||||
}
|
||||
|
||||
static const char *underscoreAttrScope(llvm::StringRef Scope) {
|
||||
if (Scope == "clang")
|
||||
return "_Clang";
|
||||
if (Scope == "gnu")
|
||||
return "__gnu__";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static const char *noUnderscoreAttrScope(llvm::StringRef Scope) {
|
||||
if (Scope == "_Clang")
|
||||
return "clang";
|
||||
if (Scope == "__gnu__")
|
||||
return "gnu";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Sema::CodeCompleteAttribute(AttributeCommonInfo::Syntax Syntax,
|
||||
AttributeCompletion Completion,
|
||||
const IdentifierInfo *InScope) {
|
||||
if (Completion == AttributeCompletion::None)
|
||||
return;
|
||||
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
|
||||
CodeCompleter->getCodeCompletionTUInfo(),
|
||||
CodeCompletionContext::CCC_Attribute);
|
||||
|
||||
// We're going to iterate over the normalized spellings of the attribute.
|
||||
// These don't include "underscore guarding": the normalized spelling is
|
||||
// clang::foo but you can also write _Clang::__foo__.
|
||||
//
|
||||
// (Clang supports a mix like clang::__foo__ but we won't suggest it: either
|
||||
// you care about clashing with macros or you don't).
|
||||
//
|
||||
// So if we're already in a scope, we determine its canonical spellings
|
||||
// (for comparison with normalized attr spelling) and remember whether it was
|
||||
// underscore-guarded (so we know how to spell contained attributes).
|
||||
llvm::StringRef InScopeName;
|
||||
bool InScopeUnderscore = false;
|
||||
if (InScope) {
|
||||
InScopeName = InScope->getName();
|
||||
if (const char *NoUnderscore = noUnderscoreAttrScope(InScopeName)) {
|
||||
InScopeName = NoUnderscore;
|
||||
InScopeUnderscore = true;
|
||||
}
|
||||
}
|
||||
bool SyntaxSupportsGuards = Syntax == AttributeCommonInfo::AS_GNU ||
|
||||
Syntax == AttributeCommonInfo::AS_CXX11 ||
|
||||
Syntax == AttributeCommonInfo::AS_C2x;
|
||||
|
||||
llvm::DenseSet<llvm::StringRef> FoundScopes;
|
||||
auto AddCompletions = [&](const ParsedAttrInfo &A) {
|
||||
if (A.IsTargetSpecific && !A.existsInTarget(Context.getTargetInfo()))
|
||||
return;
|
||||
// FIXME: filter by langopts (diagLangOpts method requires a ParsedAttr)
|
||||
for (const auto &S : A.Spellings) {
|
||||
if (S.Syntax != Syntax)
|
||||
continue;
|
||||
llvm::StringRef Name = S.NormalizedFullName;
|
||||
llvm::StringRef Scope;
|
||||
if ((Syntax == AttributeCommonInfo::AS_CXX11 ||
|
||||
Syntax == AttributeCommonInfo::AS_C2x)) {
|
||||
std::tie(Scope, Name) = Name.split("::");
|
||||
if (Name.empty()) // oops, unscoped
|
||||
std::swap(Name, Scope);
|
||||
}
|
||||
|
||||
// Do we just want a list of scopes rather than attributes?
|
||||
if (Completion == AttributeCompletion::Scope) {
|
||||
// Make sure to emit each scope only once.
|
||||
if (!Scope.empty() && FoundScopes.insert(Scope).second) {
|
||||
Results.AddResult(
|
||||
CodeCompletionResult(Results.getAllocator().CopyString(Scope)));
|
||||
// Include alternate form (__gnu__ instead of gnu).
|
||||
if (const char *Scope2 = underscoreAttrScope(Scope))
|
||||
Results.AddResult(CodeCompletionResult(Scope2));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// If a scope was specified, it must match but we don't need to print it.
|
||||
if (!InScopeName.empty()) {
|
||||
if (Scope != InScopeName)
|
||||
continue;
|
||||
Scope = "";
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// 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()) {
|
||||
const char *GuardedScope = underscoreAttrScope(Scope);
|
||||
if (!GuardedScope)
|
||||
continue;
|
||||
Guarded.append(GuardedScope);
|
||||
Guarded.append("::");
|
||||
}
|
||||
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.
|
||||
}
|
||||
};
|
||||
|
||||
for (const auto *A : ParsedAttrInfo::getAllBuiltin())
|
||||
AddCompletions(*A);
|
||||
for (const auto &Entry : ParsedAttrInfoRegistry::entries())
|
||||
AddCompletions(*Entry.instantiate());
|
||||
|
||||
HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
|
||||
Results.data(), Results.size());
|
||||
}
|
||||
|
||||
struct Sema::CodeCompleteExpressionData {
|
||||
CodeCompleteExpressionData(QualType PreferredType = QualType(),
|
||||
bool IsParenthesized = false)
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
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: COMPLETION: clang::convergent
|
||||
// STD-NOT: COMPLETION: convergent
|
||||
// STD-NOT: COMPLETION: gnu::__used__
|
||||
// STD: COMPLETION: gnu::used
|
||||
// STD-NOT: COMPLETION: used
|
||||
// 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
|
||||
int b [[__gnu__::used]];
|
||||
// RUN: %clang_cc1 -code-completion-at=%s:22:18 %s | FileCheck --check-prefix=STD-NSU %s
|
||||
// STD-NSU: COMPLETION: __used__
|
||||
// STD-NSU-NOT: COMPLETION: used
|
||||
|
||||
int c [[using gnu: used]];
|
||||
// RUN: %clang_cc1 -code-completion-at=%s:27:15 %s | FileCheck --check-prefix=STD-USING %s
|
||||
// STD-USING: COMPLETION: __gnu__
|
||||
// STD-USING: COMPLETION: _Clang
|
||||
// STD-USING-NOT: COMPLETION: carries_dependency
|
||||
// STD-USING: COMPLETION: clang
|
||||
// STD-USING-NOT: COMPLETION: clang::
|
||||
// STD-USING-NOT: COMPLETION: gnu::
|
||||
// STD-USING: COMPLETION: gnu
|
||||
// RUN: %clang_cc1 -code-completion-at=%s:27:20 %s | FileCheck --check-prefix=STD-NS %s
|
||||
|
||||
int d __attribute__((used));
|
||||
// RUN: %clang_cc1 -code-completion-at=%s:38: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
|
||||
|
||||
#pragma clang attribute push (__attribute__((internal_linkage)), apply_to=variable)
|
||||
int e;
|
||||
#pragma clang attribute pop
|
||||
// RUN: %clang_cc1 -code-completion-at=%s:51:46 %s | FileCheck --check-prefix=PRAGMA %s
|
||||
// PRAGMA: internal_linkage
|
||||
|
||||
#ifdef MS_EXT
|
||||
int __declspec(thread) f;
|
||||
// RUN: %clang_cc1 -fms-extensions -DMS_EXT -code-completion-at=%s:58: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
|
||||
|
||||
[uuid("123e4567-e89b-12d3-a456-426614174000")] struct g;
|
||||
// RUN: %clang_cc1 -fms-extensions -DMS_EXT -code-completion-at=%s:68: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
|
||||
#endif // MS_EXT
|
||||
|
||||
void foo() {
|
||||
[[omp::sequence(directive(parallel), directive(critical))]]
|
||||
{}
|
||||
}
|
||||
// FIXME: support for omp attributes would be nice.
|
||||
// RUN: %clang_cc1 -fopenmp -code-completion-at=%s:79:5 %s | FileCheck --check-prefix=OMP-NS --allow-empty %s
|
||||
// OMP-NS-NOT: omp
|
||||
// RUN: %clang_cc1 -fopenmp -code-completion-at=%s:79:10 %s | FileCheck --check-prefix=OMP-ATTR --allow-empty %s
|
||||
// OMP-ATTR-NOT: sequence
|
||||
// RUN: %clang_cc1 -fopenmp -code-completion-at=%s:79:19 %s | FileCheck --check-prefix=OMP-NESTED --allow-empty %s
|
||||
// OMP-NESTED-NOT: directive
|
|
@ -541,6 +541,7 @@ static unsigned long long getContextsForContextKind(
|
|||
case CodeCompletionContext::CCC_MacroName:
|
||||
case CodeCompletionContext::CCC_PreprocessorExpression:
|
||||
case CodeCompletionContext::CCC_PreprocessorDirective:
|
||||
case CodeCompletionContext::CCC_Attribute:
|
||||
case CodeCompletionContext::CCC_TypeQualifiers: {
|
||||
//Only Clang results should be accepted, so we'll set all of the other
|
||||
//context bits to 0 (i.e. the empty set)
|
||||
|
|
Loading…
Reference in New Issue