Repository: llvm/llvm-project
File: clang/lib/Sema/SemaCXXScopeSpec.cpp (C++)

Code before:
    if (!Found.isSingleResult())
      return nullptr;

    NamedDecl *Result = Found.getFoundDecl();
    if (isAcceptableNestedNameSpecifier(Result))
      return Result;
  }
  return nullptr;
}

namespace {

// Callback to only accept typo corrections that can be a valid C++ member
// initializer: either a non-static field member or a base class.
class NestedNameSpecifierValidatorCCC final
    : public CorrectionCandidateCallback {
public:
  explicit NestedNameSpecifierValidatorCCC(Sema &SRef)
      : SRef(SRef) {}

  bool ValidateCandidate(const TypoCorrection &candidate) override {
    return SRef.isAcceptableNestedNameSpecifier(candidate.getCorrectionDecl());
  }

  std::unique_ptr<CorrectionCandidateCallback> clone() override {
    return std::make_unique<NestedNameSpecifierValidatorCCC>(*this);
  }

 private:
  Sema &SRef;
};

}

[[nodiscard]] static bool ExtendNestedNameSpecifier(Sema &S, CXXScopeSpec &SS,
                                                    const NamedDecl *ND,
                                                    SourceLocation NameLoc,
                                                    SourceLocation CCLoc) {
  TypeLocBuilder TLB;
  QualType T;
  if (const auto *USD = dyn_cast<UsingShadowDecl>(ND)) {
    T = S.Context.getUsingType(ElaboratedTypeKeyword::None, SS.getScopeRep(),
                               USD);
    TLB.push<UsingTypeLoc>(T).set(/*ElaboratedKeywordLoc=*/SourceLocation(),
                                  SS.getWithLocInContext(S.Context), NameLoc);
  } else if (const auto *TD = dyn_cast<TypeDecl>(ND)) {
    T = S.Context.getTypeDeclType(ElaboratedTypeKeyword::None, SS.getScopeRep(),
                                  TD);
    switch (T->getTypeClass()) {
    case Type::Record:
    case Type::InjectedClassName:

Review comment (suggestion):
This has four cases but we only have one test, we should really have four tests that cover all combinations to ensure it works as expected. 

Code after:
    if (!Found.isSingleResult())
      return nullptr;

    NamedDecl *Result = Found.getFoundDecl();
    if (isAcceptableNestedNameSpecifier(Result))
      return Result;
  }
  return nullptr;
}

namespace {

// Callback to only accept typo corrections that can be a valid C++ member
// initializer: either a non-static field member or a base class.
class NestedNameSpecifierValidatorCCC final
    : public CorrectionCandidateCallback {
public:
  explicit NestedNameSpecifierValidatorCCC(Sema &SRef, bool HasQualifier)
      : SRef(SRef), HasQualifier(HasQualifier) {}

  bool ValidateCandidate(const TypoCorrection &candidate) override {
    const NamedDecl *ND = candidate.getCorrectionDecl();
    if (!SRef.isAcceptableNestedNameSpecifier(ND))
      return false;
    // A template type parameter cannot have a nested name specifier.
    if (HasQualifier && isa<TemplateTypeParmDecl>(ND))
      return false;
    return true;
  }

  std::unique_ptr<CorrectionCandidateCallback> clone() override {
    return std::make_unique<NestedNameSpecifierValidatorCCC>(*this);
  }

 private:
  Sema &SRef;
  bool HasQualifier;
};

}

[[nodiscard]] static bool ExtendNestedNameSpecifier(Sema &S, CXXScopeSpec &SS,
                                                    const NamedDecl *ND,
                                                    SourceLocation NameLoc,
                                                    SourceLocation CCLoc) {
  TypeLocBuilder TLB;
  QualType T;
  if (const auto *USD = dyn_cast<UsingShadowDecl>(ND)) {
    T = S.Context.getUsingType(ElaboratedTypeKeyword::None, SS.getScopeRep(),
                               USD);
    TLB.push<UsingTypeLoc>(T).set(/*ElaboratedKeywordLoc=*/SourceLocation(),